181ad8388SMartin Matuska ///////////////////////////////////////////////////////////////////////////////
281ad8388SMartin Matuska //
381ad8388SMartin Matuska /// \file       stream_flags_decoder.c
481ad8388SMartin Matuska /// \brief      Decodes Stream Header and Stream Footer from .xz files
581ad8388SMartin Matuska //
681ad8388SMartin Matuska //  Author:     Lasse Collin
781ad8388SMartin Matuska //
82f9cd13dSXin LI //  This file has been put into the public domain.
92f9cd13dSXin LI //  You can do whatever you want with this file.
102f9cd13dSXin LI //
1181ad8388SMartin Matuska ///////////////////////////////////////////////////////////////////////////////
1281ad8388SMartin Matuska 
1381ad8388SMartin Matuska #include "stream_flags_common.h"
1481ad8388SMartin Matuska 
1581ad8388SMartin Matuska 
1681ad8388SMartin Matuska static bool
stream_flags_decode(lzma_stream_flags * options,const uint8_t * in)1781ad8388SMartin Matuska stream_flags_decode(lzma_stream_flags *options, const uint8_t *in)
1881ad8388SMartin Matuska {
1981ad8388SMartin Matuska 	// Reserved bits must be unset.
2081ad8388SMartin Matuska 	if (in[0] != 0x00 || (in[1] & 0xF0))
2181ad8388SMartin Matuska 		return true;
2281ad8388SMartin Matuska 
2381ad8388SMartin Matuska 	options->version = 0;
2481ad8388SMartin Matuska 	options->check = in[1] & 0x0F;
2581ad8388SMartin Matuska 
2681ad8388SMartin Matuska 	return false;
2781ad8388SMartin Matuska }
2881ad8388SMartin Matuska 
2981ad8388SMartin Matuska 
3081ad8388SMartin Matuska extern LZMA_API(lzma_ret)
lzma_stream_header_decode(lzma_stream_flags * options,const uint8_t * in)3181ad8388SMartin Matuska lzma_stream_header_decode(lzma_stream_flags *options, const uint8_t *in)
3281ad8388SMartin Matuska {
3381ad8388SMartin Matuska 	// Magic
3481ad8388SMartin Matuska 	if (memcmp(in, lzma_header_magic, sizeof(lzma_header_magic)) != 0)
3581ad8388SMartin Matuska 		return LZMA_FORMAT_ERROR;
3681ad8388SMartin Matuska 
3781ad8388SMartin Matuska 	// Verify the CRC32 so we can distinguish between corrupt
3881ad8388SMartin Matuska 	// and unsupported files.
3981ad8388SMartin Matuska 	const uint32_t crc = lzma_crc32(in + sizeof(lzma_header_magic),
4081ad8388SMartin Matuska 			LZMA_STREAM_FLAGS_SIZE, 0);
41a8675d92SXin LI 	if (crc != read32le(in + sizeof(lzma_header_magic)
4273ed8e77SXin LI 			+ LZMA_STREAM_FLAGS_SIZE)) {
4373ed8e77SXin LI #ifndef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
4481ad8388SMartin Matuska 		return LZMA_DATA_ERROR;
4573ed8e77SXin LI #endif
4673ed8e77SXin LI 	}
4781ad8388SMartin Matuska 
4881ad8388SMartin Matuska 	// Stream Flags
4981ad8388SMartin Matuska 	if (stream_flags_decode(options, in + sizeof(lzma_header_magic)))
5081ad8388SMartin Matuska 		return LZMA_OPTIONS_ERROR;
5181ad8388SMartin Matuska 
5281ad8388SMartin Matuska 	// Set Backward Size to indicate unknown value. That way
5381ad8388SMartin Matuska 	// lzma_stream_flags_compare() can be used to compare Stream Header
5481ad8388SMartin Matuska 	// and Stream Footer while keeping it useful also for comparing
5581ad8388SMartin Matuska 	// two Stream Footers.
5681ad8388SMartin Matuska 	options->backward_size = LZMA_VLI_UNKNOWN;
5781ad8388SMartin Matuska 
5881ad8388SMartin Matuska 	return LZMA_OK;
5981ad8388SMartin Matuska }
6081ad8388SMartin Matuska 
6181ad8388SMartin Matuska 
6281ad8388SMartin Matuska extern LZMA_API(lzma_ret)
lzma_stream_footer_decode(lzma_stream_flags * options,const uint8_t * in)6381ad8388SMartin Matuska lzma_stream_footer_decode(lzma_stream_flags *options, const uint8_t *in)
6481ad8388SMartin Matuska {
6581ad8388SMartin Matuska 	// Magic
6681ad8388SMartin Matuska 	if (memcmp(in + sizeof(uint32_t) * 2 + LZMA_STREAM_FLAGS_SIZE,
6781ad8388SMartin Matuska 			lzma_footer_magic, sizeof(lzma_footer_magic)) != 0)
6881ad8388SMartin Matuska 		return LZMA_FORMAT_ERROR;
6981ad8388SMartin Matuska 
7081ad8388SMartin Matuska 	// CRC32
7181ad8388SMartin Matuska 	const uint32_t crc = lzma_crc32(in + sizeof(uint32_t),
7281ad8388SMartin Matuska 			sizeof(uint32_t) + LZMA_STREAM_FLAGS_SIZE, 0);
7373ed8e77SXin LI 	if (crc != read32le(in)) {
7473ed8e77SXin LI #ifndef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
7581ad8388SMartin Matuska 		return LZMA_DATA_ERROR;
7673ed8e77SXin LI #endif
7773ed8e77SXin LI 	}
7881ad8388SMartin Matuska 
7981ad8388SMartin Matuska 	// Stream Flags
8081ad8388SMartin Matuska 	if (stream_flags_decode(options, in + sizeof(uint32_t) * 2))
8181ad8388SMartin Matuska 		return LZMA_OPTIONS_ERROR;
8281ad8388SMartin Matuska 
8381ad8388SMartin Matuska 	// Backward Size
84a8675d92SXin LI 	options->backward_size = read32le(in + sizeof(uint32_t));
8581ad8388SMartin Matuska 	options->backward_size = (options->backward_size + 1) * 4;
8681ad8388SMartin Matuska 
8781ad8388SMartin Matuska 	return LZMA_OK;
8881ad8388SMartin Matuska }
89