aboutsummaryrefslogtreecommitdiff
path: root/src/liblzma/common/alignment.c
blob: c80e5fabb08de4539fb905755487ea1b4266dc7a (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
///////////////////////////////////////////////////////////////////////////////
//
/// \file       alignment.c
/// \brief      Calculates preferred alignments of different filters
//
//  Copyright (C) 2007 Lasse Collin
//
//  This library is free software; you can redistribute it and/or
//  modify it under the terms of the GNU Lesser General Public
//  License as published by the Free Software Foundation; either
//  version 2.1 of the License, or (at your option) any later version.
//
//  This library is distributed in the hope that it will be useful,
//  but WITHOUT ANY WARRANTY; without even the implied warranty of
//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
//  Lesser General Public License for more details.
//
///////////////////////////////////////////////////////////////////////////////

#include "common.h"


extern LZMA_API uint32_t
lzma_alignment_input(const lzma_options_filter *filters, uint32_t guess)
{
	for (size_t i = 0; filters[i].id != LZMA_VLI_VALUE_UNKNOWN; ++i) {
		switch (filters[i].id) {
		case LZMA_FILTER_DELTA:
			// The same as the input, check the next filter.
			continue;

		case LZMA_FILTER_SUBBLOCK:
			if (filters[i].options == NULL)
				return LZMA_SUBBLOCK_ALIGNMENT_DEFAULT;
			else
				return ((const lzma_options_subblock *)(
					filters[i].options))->alignment;

		case LZMA_FILTER_X86:
			return 1;

		case LZMA_FILTER_ARMTHUMB:
			return 2;

		case LZMA_FILTER_POWERPC:
		case LZMA_FILTER_ARM:
		case LZMA_FILTER_SPARC:
			return 4;

		case LZMA_FILTER_IA64:
			return 16;

		case LZMA_FILTER_LZMA: {
			const lzma_options_lzma *lzma = filters[i].options;
			return 1 << MAX(lzma->pos_bits,
					lzma->literal_pos_bits);
		}

		default:
			return UINT32_MAX;
		}
	}

	return guess;
}


extern LZMA_API uint32_t
lzma_alignment_output(const lzma_options_filter *filters, uint32_t guess)
{
	if (filters[0].id == LZMA_VLI_VALUE_UNKNOWN)
		return UINT32_MAX;

	// Find the last filter in the chain.
	size_t i = 0;
	while (filters[i + 1].id != LZMA_VLI_VALUE_UNKNOWN)
		++i;

	do {
		switch (filters[i].id) {
		case LZMA_FILTER_DELTA:
			// It's the same as the input alignment, so
			// check the next filter.
			continue;

		case LZMA_FILTER_SUBBLOCK:
			if (filters[i].options == NULL)
				return LZMA_SUBBLOCK_ALIGNMENT_DEFAULT;
			else
				return ((const lzma_options_subblock *)(
					filters[i].options))->alignment;

		case LZMA_FILTER_X86:
		case LZMA_FILTER_LZMA:
			return 1;

		case LZMA_FILTER_ARMTHUMB:
			return 2;

		case LZMA_FILTER_POWERPC:
		case LZMA_FILTER_ARM:
		case LZMA_FILTER_SPARC:
			return 4;

		case LZMA_FILTER_IA64:
			return 16;

		default:
			return UINT32_MAX;
		}
	} while (i-- != 0);

	// If we get here, we have the same alignment as the input data.
	return guess;
}