Rizin
unix-like reverse engineering framework and cli tools
index.c File Reference

Handling of .xz Indexes and some other Stream information. More...

#include "index.h"
#include "stream_flags_common.h"

Go to the source code of this file.

Classes

struct  index_tree_node_s
 
struct  index_tree
 AVL tree to hold index_stream or index_group structures. More...
 
struct  index_record
 
struct  index_group
 
struct  index_stream
 
struct  lzma_index_s
 
struct  index_cat_info
 Structure to pass info to index_cat_helper() More...
 

Macros

#define INDEX_GROUP_SIZE   512
 How many Records to allocate at once. More...
 
#define PREALLOC_MAX   ((SIZE_MAX - sizeof(index_group)) / sizeof(index_record))
 How many Records can be allocated at once at maximum. More...
 

Typedefs

typedef struct index_tree_node_s index_tree_node
 Base structure for index_stream and index_group structures. More...
 

Enumerations

enum  {
  ITER_INDEX , ITER_STREAM , ITER_GROUP , ITER_RECORD ,
  ITER_METHOD
}
 Indexing for lzma_index_iter.internal[]. More...
 
enum  { ITER_METHOD_NORMAL , ITER_METHOD_NEXT , ITER_METHOD_LEFTMOST }
 Values for lzma_index_iter.internal[ITER_METHOD].s. More...
 

Functions

static void index_tree_init (index_tree *tree)
 
static void index_tree_node_end (index_tree_node *node, const lzma_allocator *allocator, void(*free_func)(void *node, const lzma_allocator *allocator))
 Helper for index_tree_end() More...
 
static void index_tree_end (index_tree *tree, const lzma_allocator *allocator, void(*free_func)(void *node, const lzma_allocator *allocator))
 
static void index_tree_append (index_tree *tree, index_tree_node *node)
 
static void * index_tree_next (const index_tree_node *node)
 Get the next node in the tree. Return NULL if there are no more nodes. More...
 
static void * index_tree_locate (const index_tree *tree, lzma_vli target)
 
static index_streamindex_stream_init (lzma_vli compressed_base, lzma_vli uncompressed_base, uint32_t stream_number, lzma_vli block_number_base, const lzma_allocator *allocator)
 Allocate and initialize a new Stream using the given base offsets. More...
 
static void index_stream_end (void *node, const lzma_allocator *allocator)
 Free the memory allocated for a Stream and its Record groups. More...
 
static lzma_indexindex_init_plain (const lzma_allocator *allocator)
 
 LZMA_API (lzma_index *)
 
 LZMA_API (void)
 
void lzma_index_prealloc (lzma_index *i, lzma_vli records)
 
 LZMA_API (uint64_t)
 Calculate approximate memory usage of easy encoder. More...
 
static lzma_vli index_file_size (lzma_vli compressed_base, lzma_vli unpadded_sum, lzma_vli record_count, lzma_vli index_list_size, lzma_vli stream_padding)
 
 LZMA_API (uint32_t)
 
uint32_t lzma_index_padding_size (const lzma_index *i)
 
 LZMA_API (lzma_ret)
 
static void index_cat_helper (const index_cat_info *info, index_stream *this)
 
static index_streamindex_dup_stream (const index_stream *src, const lzma_allocator *allocator)
 Duplicate an index_stream. More...
 
static void iter_set_info (lzma_index_iter *iter)
 
 LZMA_API (lzma_bool)
 

Detailed Description

Handling of .xz Indexes and some other Stream information.

Definition in file index.c.

Macro Definition Documentation

◆ INDEX_GROUP_SIZE

#define INDEX_GROUP_SIZE   512

How many Records to allocate at once.

This should be big enough to avoid making lots of tiny allocations but small enough to avoid too much unused memory at once.

Definition at line 21 of file index.c.

◆ PREALLOC_MAX

#define PREALLOC_MAX   ((SIZE_MAX - sizeof(index_group)) / sizeof(index_record))

How many Records can be allocated at once at maximum.

Definition at line 25 of file index.c.

Typedef Documentation

◆ index_tree_node

Base structure for index_stream and index_group structures.

Definition at line 1 of file index.c.

Enumeration Type Documentation

◆ anonymous enum

anonymous enum

Indexing for lzma_index_iter.internal[].

Enumerator
ITER_INDEX 
ITER_STREAM 
ITER_GROUP 
ITER_RECORD 
ITER_METHOD 

Definition at line 960 of file index.c.

960  {
961  ITER_INDEX,
962  ITER_STREAM,
963  ITER_GROUP,
964  ITER_RECORD,
965  ITER_METHOD,
966 };
@ ITER_RECORD
Definition: index.c:964
@ ITER_STREAM
Definition: index.c:962
@ ITER_INDEX
Definition: index.c:961
@ ITER_GROUP
Definition: index.c:963
@ ITER_METHOD
Definition: index.c:965

◆ anonymous enum

anonymous enum

Values for lzma_index_iter.internal[ITER_METHOD].s.

Enumerator
ITER_METHOD_NORMAL 
ITER_METHOD_NEXT 
ITER_METHOD_LEFTMOST 

Definition at line 970 of file index.c.

970  {
974 };
@ ITER_METHOD_NORMAL
Definition: index.c:971
@ ITER_METHOD_LEFTMOST
Definition: index.c:973
@ ITER_METHOD_NEXT
Definition: index.c:972

Function Documentation

◆ index_cat_helper()

static void index_cat_helper ( const index_cat_info info,
index_stream this 
)
static

Add the Stream nodes from the source index to dest using recursion. Simplest iterative traversal of the source tree wouldn't work, because we update the pointers in nodes when moving them to the destination tree.

Definition at line 745 of file index.c.

746 {
747  index_stream *left = (index_stream *)(this->node.left);
748  index_stream *right = (index_stream *)(this->node.right);
749 
750  if (left != NULL)
751  index_cat_helper(info, left);
752 
753  this->node.uncompressed_base += info->uncompressed_size;
754  this->node.compressed_base += info->file_size;
755  this->number += info->stream_number_add;
756  this->block_number_base += info->block_number_add;
757  index_tree_append(info->streams, &this->node);
758 
759  if (right != NULL)
760  index_cat_helper(info, right);
761 
762  return;
763 }
RzBinInfo * info(RzBinFile *bf)
Definition: bin_ne.c:86
#define NULL
Definition: cris-opc.c:27
static void index_tree_append(index_tree *tree, index_tree_node *node)
Definition: index.c:230
static void index_cat_helper(const index_cat_info *info, index_stream *this)
Definition: index.c:745
index_tree_node node
Every index_stream is a node in the tree of Streams.
Definition: index.c:109

References index_tree_node_s::compressed_base, index_tree_append(), info(), index_tree_node_s::left, NULL, index_tree_node_s::right, and index_tree_node_s::uncompressed_base.

◆ index_dup_stream()

static index_stream* index_dup_stream ( const index_stream src,
const lzma_allocator allocator 
)
static

Duplicate an index_stream.

Definition at line 865 of file index.c.

866 {
867  // Catch a somewhat theoretical integer overflow.
869  return NULL;
870 
871  // Allocate and initialize a new Stream.
872  index_stream *dest = index_stream_init(src->node.compressed_base,
873  src->node.uncompressed_base, src->number,
874  src->block_number_base, allocator);
875  if (dest == NULL)
876  return NULL;
877 
878  // Copy the overall information.
879  dest->record_count = src->record_count;
880  dest->index_list_size = src->index_list_size;
881  dest->stream_flags = src->stream_flags;
882  dest->stream_padding = src->stream_padding;
883 
884  // Return if there are no groups to duplicate.
885  if (src->groups.leftmost == NULL)
886  return dest;
887 
888  // Allocate memory for the Records. We put all the Records into
889  // a single group. It's simplest and also tends to make
890  // lzma_index_locate() a little bit faster with very big Indexes.
891  index_group *destg = lzma_alloc(sizeof(index_group)
892  + src->record_count * sizeof(index_record),
893  allocator);
894  if (destg == NULL) {
896  return NULL;
897  }
898 
899  // Initialize destg.
900  destg->node.uncompressed_base = 0;
901  destg->node.compressed_base = 0;
902  destg->number_base = 1;
903  destg->allocated = src->record_count;
904  destg->last = src->record_count - 1;
905 
906  // Go through all the groups in src and copy the Records into destg.
907  const index_group *srcg = (const index_group *)(src->groups.leftmost);
908  size_t i = 0;
909  do {
910  memcpy(destg->records + i, srcg->records,
911  (srcg->last + 1) * sizeof(index_record));
912  i += srcg->last + 1;
913  srcg = index_tree_next(&srcg->node);
914  } while (srcg != NULL);
915 
916  assert(i == destg->allocated);
917 
918  // Add the group to the new Stream.
919  index_tree_append(&dest->groups, &destg->node);
920 
921  return dest;
922 }
lzma_index ** i
Definition: index.h:629
lzma_index * src
Definition: index.h:567
const lzma_allocator * allocator
Definition: block.h:377
static void index_stream_end(void *node, const lzma_allocator *allocator)
Free the memory allocated for a Stream and its Record groups.
Definition: index.c:370
static index_stream * index_stream_init(lzma_vli compressed_base, lzma_vli uncompressed_base, uint32_t stream_number, lzma_vli block_number_base, const lzma_allocator *allocator)
Allocate and initialize a new Stream using the given base offsets.
Definition: index.c:340
#define PREALLOC_MAX
How many Records can be allocated at once at maximum.
Definition: index.c:25
static void * index_tree_next(const index_tree_node *node)
Get the next node in the tree. Return NULL if there are no more nodes.
Definition: index.c:294
memcpy(mem, inblock.get(), min(CONTAINING_RECORD(inblock.get(), MEMBLOCK, data) ->size, size))
char * dest
Definition: lz4.h:697
assert(limit<=UINT32_MAX/2)
size_t last
Index of the last Record in use.
Definition: index.c:82
lzma_vli number_base
Number of Blocks in this Stream before this group.
Definition: index.c:76
size_t allocated
Number of Records that can be put in records[].
Definition: index.c:79
index_tree_node node
Every Record group is part of index_stream.groups tree.
Definition: index.c:73
index_record records[]
Definition: index.c:102
lzma_vli uncompressed_base
Definition: index.c:34
lzma_vli compressed_base
Compressed start offset of this Stream or Block.
Definition: index.c:37
lzma_vli index_list_size
Definition: index.c:166
lzma_vli record_count
Total number of Records in all Streams in this lzma_index.
Definition: index.c:158
void * lzma_alloc(size_t size, const lzma_allocator *allocator) lzma_attribute((__malloc__)) lzma_attr_alloc_size(1)
Allocates memory.

References index_group::allocated, allocator, assert(), index_tree_node_s::compressed_base, dest, i, lzma_index_s::index_list_size, index_stream_end(), index_stream_init(), index_tree_append(), index_tree_next(), index_group::last, lzma_alloc(), memcpy(), index_group::node, NULL, index_group::number_base, PREALLOC_MAX, lzma_index_s::record_count, index_group::records, src, and index_tree_node_s::uncompressed_base.

Referenced by LZMA_API().

◆ index_file_size()

static lzma_vli index_file_size ( lzma_vli  compressed_base,
lzma_vli  unpadded_sum,
lzma_vli  record_count,
lzma_vli  index_list_size,
lzma_vli  stream_padding 
)
static

Definition at line 536 of file index.c.

539 {
540  // Earlier Streams and Stream Paddings + Stream Header
541  // + Blocks + Index + Stream Footer + Stream Padding
542  //
543  // This might go over LZMA_VLI_MAX due to too big unpadded_sum
544  // when this function is used in lzma_index_append().
545  lzma_vli file_size = compressed_base + 2 * LZMA_STREAM_HEADER_SIZE
546  + stream_padding + vli_ceil4(unpadded_sum);
547  if (file_size > LZMA_VLI_MAX)
548  return LZMA_VLI_UNKNOWN;
549 
550  // The same applies here.
551  file_size += index_size(record_count, index_list_size);
552  if (file_size > LZMA_VLI_MAX)
553  return LZMA_VLI_UNKNOWN;
554 
555  return file_size;
556 }
static lzma_vli vli_ceil4(lzma_vli vli)
Round the variable-length integer to the next multiple of four.
Definition: index.h:39
static lzma_vli index_size(lzma_vli count, lzma_vli index_list_size)
Calculate the size of the Index field including Index Padding.
Definition: index.h:57
#define LZMA_STREAM_HEADER_SIZE
Size of Stream Header and Stream Footer.
Definition: stream_flags.h:27
uint64_t stream_padding
Definition: list.c:107
uint64_t lzma_vli
Variable-length integer type.
Definition: vli.h:63
#define LZMA_VLI_UNKNOWN
VLI value to denote that the value is unknown.
Definition: vli.h:39
#define LZMA_VLI_MAX
Maximum supported value of a variable-length integer.
Definition: vli.h:34

References index_size(), LZMA_STREAM_HEADER_SIZE, LZMA_VLI_MAX, LZMA_VLI_UNKNOWN, stream_padding, and vli_ceil4().

◆ index_init_plain()

static lzma_index* index_init_plain ( const lzma_allocator allocator)
static

Definition at line 380 of file index.c.

381 {
383  if (i != NULL) {
385  i->uncompressed_size = 0;
386  i->total_size = 0;
387  i->record_count = 0;
388  i->index_list_size = 0;
390  i->checks = 0;
391  }
392 
393  return i;
394 }
#define INDEX_GROUP_SIZE
How many Records to allocate at once.
Definition: index.c:21
static void index_tree_init(index_tree *tree)
Definition: index.c:182
lzma_vli total_size
Total size of all the Blocks in the Stream(s)
Definition: index.c:155
index_tree streams
Definition: index.c:149
size_t prealloc
Definition: index.c:171
lzma_vli uncompressed_size
Uncompressed size of all the Blocks in the Stream(s)
Definition: index.c:152
uint32_t checks
Definition: index.c:177

References allocator, lzma_index_s::checks, i, INDEX_GROUP_SIZE, lzma_index_s::index_list_size, index_tree_init(), lzma_alloc(), NULL, lzma_index_s::prealloc, lzma_index_s::record_count, lzma_index_s::streams, lzma_index_s::total_size, and lzma_index_s::uncompressed_size.

Referenced by LZMA_API().

◆ index_stream_end()

static void index_stream_end ( void *  node,
const lzma_allocator allocator 
)
static

Free the memory allocated for a Stream and its Record groups.

Definition at line 370 of file index.c.

371 {
372  index_stream *s = node;
373  index_tree_end(&s->groups, allocator, &lzma_free);
375  return;
376 }
static void index_tree_end(index_tree *tree, const lzma_allocator *allocator, void(*free_func)(void *node, const lzma_allocator *allocator))
Definition: index.c:215
static RzSocket * s
Definition: rtr.c:28
void lzma_free(void *ptr, const lzma_allocator *allocator)
Frees memory.
Definition: common.c:78

References allocator, index_tree_end(), lzma_free(), and s.

Referenced by index_dup_stream(), and LZMA_API().

◆ index_stream_init()

static index_stream* index_stream_init ( lzma_vli  compressed_base,
lzma_vli  uncompressed_base,
uint32_t  stream_number,
lzma_vli  block_number_base,
const lzma_allocator allocator 
)
static

Allocate and initialize a new Stream using the given base offsets.

Definition at line 340 of file index.c.

343 {
345  if (s == NULL)
346  return NULL;
347 
348  s->node.uncompressed_base = uncompressed_base;
349  s->node.compressed_base = compressed_base;
350  s->node.parent = NULL;
351  s->node.left = NULL;
352  s->node.right = NULL;
353 
354  s->number = stream_number;
355  s->block_number_base = block_number_base;
356 
357  index_tree_init(&s->groups);
358 
359  s->record_count = 0;
360  s->index_list_size = 0;
361  s->stream_flags.version = UINT32_MAX;
362  s->stream_padding = 0;
363 
364  return s;
365 }
#define UINT32_MAX

References allocator, index_tree_init(), lzma_alloc(), NULL, s, and UINT32_MAX.

Referenced by index_dup_stream(), and LZMA_API().

◆ index_tree_append()

static void index_tree_append ( index_tree tree,
index_tree_node node 
)
static

Add a new node to the tree. node->uncompressed_base and node->compressed_base must have been set by the caller already.

Definition at line 230 of file index.c.

231 {
232  node->parent = tree->rightmost;
233  node->left = NULL;
234  node->right = NULL;
235 
236  ++tree->count;
237 
238  // Handle the special case of adding the first node.
239  if (tree->root == NULL) {
240  tree->root = node;
241  tree->leftmost = node;
242  tree->rightmost = node;
243  return;
244  }
245 
246  // The tree is always filled sequentially.
249 
250  // Add the new node after the rightmost node. It's the correct
251  // place due to the reason above.
252  tree->rightmost->right = node;
253  tree->rightmost = node;
254 
255  // Balance the AVL-tree if needed. We don't need to keep the balance
256  // factors in nodes, because we always fill the tree sequentially,
257  // and thus know the state of the tree just by looking at the node
258  // count. From the node count we can calculate how many steps to go
259  // up in the tree to find the rotation root.
260  uint32_t up = tree->count ^ (UINT32_C(1) << bsr32(tree->count));
261  if (up != 0) {
262  // Locate the root node for the rotation.
263  up = ctz32(tree->count) + 2;
264  do {
265  node = node->parent;
266  } while (--up > 0);
267 
268  // Rotate left using node as the rotation root.
269  index_tree_node *pivot = node->right;
270 
271  if (node->parent == NULL) {
272  tree->root = pivot;
273  } else {
274  assert(node->parent->right == node);
275  node->parent->right = pivot;
276  }
277 
278  pivot->parent = node->parent;
279 
280  node->right = pivot->left;
281  if (node->right != NULL)
282  node->right->parent = node;
283 
284  pivot->left = node;
285  node->parent = pivot;
286  }
287 
288  return;
289 }
unsigned int uint32_t
Definition: sftypes.h:29
#define UINT32_C(val)
index_tree_node * right
Definition: index.c:41
index_tree_node * left
Definition: index.c:40
index_tree_node * parent
Definition: index.c:39
index_tree_node * rightmost
Definition: index.c:57
uint32_t count
Number of nodes in the tree.
Definition: index.c:60
index_tree_node * leftmost
Definition: index.c:53
index_tree_node * root
Root node.
Definition: index.c:48
static uint32_t ctz32(uint32_t n)
static uint32_t bsr32(uint32_t n)

References assert(), bsr32(), index_tree_node_s::compressed_base, index_tree::count, ctz32(), index_tree_node_s::left, index_tree::leftmost, NULL, index_tree_node_s::parent, index_tree_node_s::right, index_tree::rightmost, index_tree::root, UINT32_C, and index_tree_node_s::uncompressed_base.

Referenced by index_cat_helper(), index_dup_stream(), and LZMA_API().

◆ index_tree_end()

static void index_tree_end ( index_tree tree,
const lzma_allocator allocator,
void(*)(void *node, const lzma_allocator *allocator free_func 
)
static

Free the memory allocated for a tree. Each node is freed using the given free_func which is either &lzma_free or &index_stream_end. The latter is used to free the Record groups from each index_stream before freeing the index_stream itself.

Definition at line 215 of file index.c.

217 {
218  assert(free_func != NULL);
219 
220  if (tree->root != NULL)
221  index_tree_node_end(tree->root, allocator, free_func);
222 
223  return;
224 }
static void index_tree_node_end(index_tree_node *node, const lzma_allocator *allocator, void(*free_func)(void *node, const lzma_allocator *allocator))
Helper for index_tree_end()
Definition: index.c:194

References allocator, assert(), index_tree_node_end(), NULL, and index_tree::root.

Referenced by index_stream_end(), and LZMA_API().

◆ index_tree_init()

static void index_tree_init ( index_tree tree)
static

Definition at line 182 of file index.c.

183 {
184  tree->root = NULL;
185  tree->leftmost = NULL;
186  tree->rightmost = NULL;
187  tree->count = 0;
188  return;
189 }

References index_tree::count, index_tree::leftmost, NULL, index_tree::rightmost, and index_tree::root.

Referenced by index_init_plain(), and index_stream_init().

◆ index_tree_locate()

static void* index_tree_locate ( const index_tree tree,
lzma_vli  target 
)
static

Locate a node that contains the given uncompressed offset. It is caller's job to check that target is not bigger than the uncompressed size of the tree (the last node would be returned in that case still).

Definition at line 315 of file index.c.

316 {
317  const index_tree_node *result = NULL;
318  const index_tree_node *node = tree->root;
319 
320  assert(tree->leftmost == NULL
321  || tree->leftmost->uncompressed_base == 0);
322 
323  // Consecutive nodes may have the same uncompressed_base.
324  // We must pick the rightmost one.
325  while (node != NULL) {
326  if (node->uncompressed_base > target) {
327  node = node->left;
328  } else {
329  result = node;
330  node = node->right;
331  }
332  }
333 
334  return (void *)(result);
335 }

References assert(), index_tree_node_s::left, index_tree::leftmost, NULL, index_tree_node_s::right, index_tree::root, and index_tree_node_s::uncompressed_base.

Referenced by LZMA_API().

◆ index_tree_next()

static void* index_tree_next ( const index_tree_node node)
static

Get the next node in the tree. Return NULL if there are no more nodes.

Definition at line 294 of file index.c.

295 {
296  if (node->right != NULL) {
297  node = node->right;
298  while (node->left != NULL)
299  node = node->left;
300 
301  return (void *)(node);
302  }
303 
304  while (node->parent != NULL && node->parent->right == node)
305  node = node->parent;
306 
307  return (void *)(node->parent);
308 }

References index_tree_node_s::left, NULL, index_tree_node_s::parent, and index_tree_node_s::right.

Referenced by index_dup_stream(), and LZMA_API().

◆ index_tree_node_end()

static void index_tree_node_end ( index_tree_node node,
const lzma_allocator allocator,
void(*)(void *node, const lzma_allocator *allocator free_func 
)
static

Helper for index_tree_end()

Definition at line 194 of file index.c.

196 {
197  // The tree won't ever be very huge, so recursion should be fine.
198  // 20 levels in the tree is likely quite a lot already in practice.
199  if (node->left != NULL)
200  index_tree_node_end(node->left, allocator, free_func);
201 
202  if (node->right != NULL)
203  index_tree_node_end(node->right, allocator, free_func);
204 
205  free_func(node, allocator);
206  return;
207 }

References allocator, and NULL.

Referenced by index_tree_end().

◆ iter_set_info()

static void iter_set_info ( lzma_index_iter iter)
static

Definition at line 978 of file index.c.

979 {
980  const lzma_index *i = iter->internal[ITER_INDEX].p;
981  const index_stream *stream = iter->internal[ITER_STREAM].p;
982  const index_group *group = iter->internal[ITER_GROUP].p;
983  const size_t record = iter->internal[ITER_RECORD].s;
984 
985  // lzma_index_iter.internal must not contain a pointer to the last
986  // group in the index, because that may be reallocated by
987  // lzma_index_cat().
988  if (group == NULL) {
989  // There are no groups.
990  assert(stream->groups.root == NULL);
991  iter->internal[ITER_METHOD].s = ITER_METHOD_LEFTMOST;
992 
993  } else if (i->streams.rightmost != &stream->node
994  || stream->groups.rightmost != &group->node) {
995  // The group is not not the last group in the index.
996  iter->internal[ITER_METHOD].s = ITER_METHOD_NORMAL;
997 
998  } else if (stream->groups.leftmost != &group->node) {
999  // The group isn't the only group in the Stream, thus we
1000  // know that it must have a parent group i.e. it's not
1001  // the root node.
1002  assert(stream->groups.root != &group->node);
1003  assert(group->node.parent->right == &group->node);
1004  iter->internal[ITER_METHOD].s = ITER_METHOD_NEXT;
1005  iter->internal[ITER_GROUP].p = group->node.parent;
1006 
1007  } else {
1008  // The Stream has only one group.
1009  assert(stream->groups.root == &group->node);
1010  assert(group->node.parent == NULL);
1011  iter->internal[ITER_METHOD].s = ITER_METHOD_LEFTMOST;
1012  iter->internal[ITER_GROUP].p = NULL;
1013  }
1014 
1015  // NOTE: lzma_index_iter.stream.number is lzma_vli but we use uint32_t
1016  // internally.
1017  iter->stream.number = stream->number;
1018  iter->stream.block_count = stream->record_count;
1019  iter->stream.compressed_offset = stream->node.compressed_base;
1020  iter->stream.uncompressed_offset = stream->node.uncompressed_base;
1021 
1022  // iter->stream.flags will be NULL if the Stream Flags haven't been
1023  // set with lzma_index_stream_flags().
1024  iter->stream.flags = stream->stream_flags.version == UINT32_MAX
1025  ? NULL : &stream->stream_flags;
1026  iter->stream.padding = stream->stream_padding;
1027 
1028  if (stream->groups.rightmost == NULL) {
1029  // Stream has no Blocks.
1030  iter->stream.compressed_size = index_size(0, 0)
1032  iter->stream.uncompressed_size = 0;
1033  } else {
1034  const index_group *g = (const index_group *)(
1035  stream->groups.rightmost);
1036 
1037  // Stream Header + Stream Footer + Index + Blocks
1038  iter->stream.compressed_size = 2 * LZMA_STREAM_HEADER_SIZE
1039  + index_size(stream->record_count,
1040  stream->index_list_size)
1041  + vli_ceil4(g->records[g->last].unpadded_sum);
1042  iter->stream.uncompressed_size
1043  = g->records[g->last].uncompressed_sum;
1044  }
1045 
1046  if (group != NULL) {
1047  iter->block.number_in_stream = group->number_base + record;
1048  iter->block.number_in_file = iter->block.number_in_stream
1049  + stream->block_number_base;
1050 
1051  iter->block.compressed_stream_offset
1052  = record == 0 ? group->node.compressed_base
1053  : vli_ceil4(group->records[
1054  record - 1].unpadded_sum);
1055  iter->block.uncompressed_stream_offset
1056  = record == 0 ? group->node.uncompressed_base
1057  : group->records[record - 1].uncompressed_sum;
1058 
1059  iter->block.uncompressed_size
1060  = group->records[record].uncompressed_sum
1061  - iter->block.uncompressed_stream_offset;
1062  iter->block.unpadded_size
1063  = group->records[record].unpadded_sum
1064  - iter->block.compressed_stream_offset;
1065  iter->block.total_size = vli_ceil4(iter->block.unpadded_size);
1066 
1067  iter->block.compressed_stream_offset
1069 
1070  iter->block.compressed_file_offset
1071  = iter->block.compressed_stream_offset
1072  + iter->stream.compressed_offset;
1073  iter->block.uncompressed_file_offset
1074  = iter->block.uncompressed_stream_offset
1075  + iter->stream.uncompressed_offset;
1076  }
1077 
1078  return;
1079 }
struct @667 g
voidpf stream
Definition: ioapi.h:138
lzma_vli unpadded_sum
Definition: index.c:67
lzma_vli uncompressed_sum
Definition: index.c:66
Definition: tar.h:52

References assert(), index_tree_node_s::compressed_base, g, i, index_size(), ITER_GROUP, ITER_INDEX, ITER_METHOD, ITER_METHOD_LEFTMOST, ITER_METHOD_NEXT, ITER_METHOD_NORMAL, ITER_RECORD, ITER_STREAM, LZMA_STREAM_HEADER_SIZE, index_group::node, NULL, index_group::number_base, index_tree_node_s::parent, index_group::records, index_tree_node_s::right, index_tree::rightmost, lzma_index_s::streams, UINT32_MAX, index_tree_node_s::uncompressed_base, index_record::uncompressed_sum, index_record::unpadded_sum, and vli_ceil4().

Referenced by LZMA_API().

◆ LZMA_API() [1/6]

LZMA_API ( lzma_bool  )

Definition at line 1102 of file index.c.

1104 {
1105  // Catch unsupported mode values.
1106  if ((unsigned int)(mode) > LZMA_INDEX_ITER_NONEMPTY_BLOCK)
1107  return true;
1108 
1109  const lzma_index *i = iter->internal[ITER_INDEX].p;
1110  const index_stream *stream = iter->internal[ITER_STREAM].p;
1111  const index_group *group = NULL;
1112  size_t record = iter->internal[ITER_RECORD].s;
1113 
1114  // If we are being asked for the next Stream, leave group to NULL
1115  // so that the rest of the this function thinks that this Stream
1116  // has no groups and will thus go to the next Stream.
1117  if (mode != LZMA_INDEX_ITER_STREAM) {
1118  // Get the pointer to the current group. See iter_set_inf()
1119  // for explanation.
1120  switch (iter->internal[ITER_METHOD].s) {
1121  case ITER_METHOD_NORMAL:
1122  group = iter->internal[ITER_GROUP].p;
1123  break;
1124 
1125  case ITER_METHOD_NEXT:
1126  group = index_tree_next(iter->internal[ITER_GROUP].p);
1127  break;
1128 
1129  case ITER_METHOD_LEFTMOST:
1130  group = (const index_group *)(
1131  stream->groups.leftmost);
1132  break;
1133  }
1134  }
1135 
1136 again:
1137  if (stream == NULL) {
1138  // We at the beginning of the lzma_index.
1139  // Locate the first Stream.
1140  stream = (const index_stream *)(i->streams.leftmost);
1141  if (mode >= LZMA_INDEX_ITER_BLOCK) {
1142  // Since we are being asked to return information
1143  // about the first a Block, skip Streams that have
1144  // no Blocks.
1145  while (stream->groups.leftmost == NULL) {
1146  stream = index_tree_next(&stream->node);
1147  if (stream == NULL)
1148  return true;
1149  }
1150  }
1151 
1152  // Start from the first Record in the Stream.
1153  group = (const index_group *)(stream->groups.leftmost);
1154  record = 0;
1155 
1156  } else if (group != NULL && record < group->last) {
1157  // The next Record is in the same group.
1158  ++record;
1159 
1160  } else {
1161  // This group has no more Records or this Stream has
1162  // no Blocks at all.
1163  record = 0;
1164 
1165  // If group is not NULL, this Stream has at least one Block
1166  // and thus at least one group. Find the next group.
1167  if (group != NULL)
1168  group = index_tree_next(&group->node);
1169 
1170  if (group == NULL) {
1171  // This Stream has no more Records. Find the next
1172  // Stream. If we are being asked to return information
1173  // about a Block, we skip empty Streams.
1174  do {
1175  stream = index_tree_next(&stream->node);
1176  if (stream == NULL)
1177  return true;
1178  } while (mode >= LZMA_INDEX_ITER_BLOCK
1179  && stream->groups.leftmost == NULL);
1180 
1181  group = (const index_group *)(
1182  stream->groups.leftmost);
1183  }
1184  }
1185 
1187  // We need to look for the next Block again if this Block
1188  // is empty.
1189  if (record == 0) {
1190  if (group->node.uncompressed_base
1191  == group->records[0].uncompressed_sum)
1192  goto again;
1193  } else if (group->records[record - 1].uncompressed_sum
1194  == group->records[record].uncompressed_sum) {
1195  goto again;
1196  }
1197  }
1198 
1199  iter->internal[ITER_STREAM].p = stream;
1200  iter->internal[ITER_GROUP].p = group;
1201  iter->internal[ITER_RECORD].s = record;
1202 
1204 
1205  return false;
1206 }
@ LZMA_INDEX_ITER_BLOCK
Get the next Block.
Definition: index.h:249
@ LZMA_INDEX_ITER_STREAM
Get the next Stream.
Definition: index.h:238
@ LZMA_INDEX_ITER_NONEMPTY_BLOCK
Get the next non-empty Block.
Definition: index.h:260
static void iter_set_info(lzma_index_iter *iter)
Definition: index.c:978
const char int mode
Definition: ioapi.h:137

References i, index_tree_next(), ITER_GROUP, ITER_INDEX, ITER_METHOD, ITER_METHOD_LEFTMOST, ITER_METHOD_NEXT, ITER_METHOD_NORMAL, ITER_RECORD, iter_set_info(), ITER_STREAM, index_tree::leftmost, LZMA_INDEX_ITER_BLOCK, LZMA_INDEX_ITER_NONEMPTY_BLOCK, LZMA_INDEX_ITER_STREAM, index_group::node, NULL, index_group::records, lzma_index_s::streams, index_tree_node_s::uncompressed_base, and index_record::uncompressed_sum.

◆ LZMA_API() [2/6]

LZMA_API ( lzma_index )

Definition at line 397 of file index.c.

399 {
401  if (i == NULL)
402  return NULL;
403 
404  index_stream *s = index_stream_init(0, 0, 1, 0, allocator);
405  if (s == NULL) {
407  return NULL;
408  }
409 
410  index_tree_append(&i->streams, &s->node);
411 
412  return i;
413 }
static lzma_index * index_init_plain(const lzma_allocator *allocator)
Definition: index.c:380

References allocator, i, index_init_plain(), index_stream_init(), index_tree_append(), lzma_free(), NULL, s, and lzma_index_s::streams.

◆ LZMA_API() [3/6]

LZMA_API ( lzma_ret  )

Definition at line 600 of file index.c.

602 {
603  if (i == NULL || stream_flags == NULL)
604  return LZMA_PROG_ERROR;
605 
606  // Validate the Stream Flags.
607  return_if_error(lzma_stream_flags_compare(
608  stream_flags, stream_flags));
609 
611  s->stream_flags = *stream_flags;
612 
613  return LZMA_OK;
614 }
#define return_if_error(expr)
Return if expression doesn't evaluate to LZMA_OK.
Definition: common.h:278
@ LZMA_PROG_ERROR
Programming error.
Definition: base.h:218
@ LZMA_OK
Operation completed successfully.
Definition: base.h:58

References i, LZMA_OK, LZMA_PROG_ERROR, NULL, return_if_error, index_tree::rightmost, s, and lzma_index_s::streams.

◆ LZMA_API() [4/6]

LZMA_API ( uint32_t  )

Definition at line 578 of file index.c.

580 {
581  uint32_t checks = i->checks;
582 
583  // Get the type of the Check of the last Stream too.
584  const index_stream *s = (const index_stream *)(i->streams.rightmost);
585  if (s->stream_flags.version != UINT32_MAX)
586  checks |= UINT32_C(1) << s->stream_flags.check;
587 
588  return checks;
589 }
uint32_t checks
Definition: list.c:109

References lzma_index_s::checks, checks, i, index_tree::rightmost, s, lzma_index_s::streams, UINT32_C, and UINT32_MAX.

◆ LZMA_API() [5/6]

LZMA_API ( uint64_t  )

Calculate approximate memory usage of easy encoder.

Get the total amount of physical memory (RAM) in bytes.

Calculate approximate memory usage of multithreaded .xz encoder.

Calculate approximate decoder memory usage of a preset.

This function is a wrapper for lzma_raw_encoder_memusage().

Parameters
presetCompression preset (level and possible flags)
Returns
Number of bytes of memory required for the given preset when encoding. If an error occurs, for example due to unsupported preset, UINT64_MAX is returned.

This function is a wrapper for lzma_raw_decoder_memusage().

Parameters
presetCompression preset (level and possible flags)
Returns
Number of bytes of memory required to decompress a file that was compressed using the given preset. If an error occurs, for example due to unsupported preset, UINT64_MAX is returned.

Since doing the encoding in threaded mode doesn't affect the memory requirements of single-threaded decompressor, you can use lzma_easy_decoder_memusage(options->preset) or lzma_raw_decoder_memusage(options->filters) to calculate the decompressor memory requirements.

Parameters
optionsCompression options
Returns
Number of bytes of memory required for encoding with the given options. If an error occurs, for example due to unsupported preset or filter chain, UINT64_MAX is returned.

Calculate approximate memory usage of easy encoder.

Get the uncompressed size of the file.

Get the total size of the file.

Get the total size of the Blocks.

Get the total size of the Stream.

Get the size of the Index field as bytes.

Get the number of Blocks.

Get the number of Streams.

Calculate the memory usage of an existing lzma_index.

On disk, the size of the Index field depends on both the number of Records stored and how big values the Records store (due to variable-length integer encoding). When the Index is kept in lzma_index structure, the memory usage depends only on the number of Records/Blocks stored in the Index(es), and in case of concatenated lzma_indexes, the number of Streams. The size in RAM is almost always significantly bigger than in the encoded form on disk.

This function calculates an approximate amount of memory needed hold the given number of Streams and Blocks in lzma_index structure. This value may vary between CPU architectures and also between liblzma versions if the internal implementation is modified.

This is a shorthand for lzma_index_memusage(lzma_index_stream_count(i), lzma_index_block_count(i)).

This returns the total number of Blocks in lzma_index. To get number of Blocks in individual Streams, use lzma_index_iter.

This is needed to verify the Backward Size field in the Stream Footer.

If multiple lzma_indexes have been combined, this works as if the Blocks were in a single Stream. This is useful if you are going to combine Blocks from multiple Streams into a single new Stream.

This doesn't include the Stream Header, Stream Footer, Stream Padding, or Index fields.

When no lzma_indexes have been combined with lzma_index_cat() and there is no Stream Padding, this function is identical to lzma_index_stream_size(). If multiple lzma_indexes have been combined, this includes also the headers of each separate Stream and the possible Stream Padding fields.

Definition at line 441 of file index.c.

443 {
444  // This calculates an upper bound that is only a little bit
445  // bigger than the exact maximum memory usage with the given
446  // parameters.
447 
448  // Typical malloc() overhead is 2 * sizeof(void *) but we take
449  // a little bit extra just in case. Using LZMA_MEMUSAGE_BASE
450  // instead would give too inaccurate estimate.
451  const size_t alloc_overhead = 4 * sizeof(void *);
452 
453  // Amount of memory needed for each Stream base structures.
454  // We assume that every Stream has at least one Block and
455  // thus at least one group.
456  const size_t stream_base = sizeof(index_stream)
457  + sizeof(index_group) + 2 * alloc_overhead;
458 
459  // Amount of memory needed per group.
460  const size_t group_base = sizeof(index_group)
461  + INDEX_GROUP_SIZE * sizeof(index_record)
462  + alloc_overhead;
463 
464  // Number of groups. There may actually be more, but that overhead
465  // has been taken into account in stream_base already.
466  const lzma_vli groups
468 
469  // Memory used by index_stream and index_group structures.
470  const uint64_t streams_mem = streams * stream_base;
471  const uint64_t groups_mem = groups * group_base;
472 
473  // Memory used by the base structure.
474  const uint64_t index_base = sizeof(lzma_index) + alloc_overhead;
475 
476  // Validate the arguments and catch integer overflows.
477  // Maximum number of Streams is "only" UINT32_MAX, because
478  // that limit is used by the tree containing the Streams.
479  const uint64_t limit = UINT64_MAX - index_base;
480  if (streams == 0 || streams > UINT32_MAX || blocks > LZMA_VLI_MAX
481  || streams > limit / stream_base
482  || groups > limit / group_base
483  || limit - streams_mem < groups_mem)
484  return UINT64_MAX;
485 
486  return index_base + streams_mem + groups_mem;
487 }
struct lzma_index_s lzma_index
Opaque data type to hold the Index(es) and other information.
Definition: index.h:37
static uint32_t const uint8_t uint32_t uint32_t limit
Definition: memcmplen.h:45
unsigned long uint64_t
Definition: sftypes.h:28
#define UINT64_MAX
uint64_t streams
Definition: list.c:103
uint64_t blocks
Definition: list.c:104

References blocks, make_dist_html::groups, INDEX_GROUP_SIZE, limit, LZMA_VLI_MAX, streams, UINT32_MAX, and UINT64_MAX.

◆ LZMA_API() [6/6]

LZMA_API ( void  )

Definition at line 416 of file index.c.

418 {
419  // NOTE: If you modify this function, check also the bottom
420  // of lzma_index_cat().
421  if (i != NULL) {
424  }
425 
426  return;
427 }

References allocator, i, index_stream_end(), index_tree_end(), lzma_free(), NULL, and lzma_index_s::streams.

◆ lzma_index_padding_size()

uint32_t lzma_index_padding_size ( const lzma_index i)

Get the size of the Index Padding field. This is needed by Index encoder and decoder, but applications should have no use for this.

Definition at line 593 of file index.c.

594 {
595  return (LZMA_VLI_C(4) - index_size_unpadded(
596  i->record_count, i->index_list_size)) & 3;
597 }
static lzma_vli index_size_unpadded(lzma_vli count, lzma_vli index_list_size)
Calculate the size of the Index field excluding Index Padding.
Definition: index.h:48
#define LZMA_VLI_C(n)
VLI constant suffix.
Definition: vli.h:49

References i, lzma_index_s::index_list_size, index_size_unpadded(), LZMA_VLI_C, and lzma_index_s::record_count.

Referenced by index_decode(), and index_encode().

◆ lzma_index_prealloc()

void lzma_index_prealloc ( lzma_index i,
lzma_vli  records 
)

Set for how many Records to allocate memory the next time lzma_index_append() needs to allocate space for a new Record. This is used only by the Index decoder.

Definition at line 431 of file index.c.

432 {
433  if (records > PREALLOC_MAX)
434  records = PREALLOC_MAX;
435 
436  i->prealloc = (size_t)(records);
437  return;
438 }
int size_t
Definition: sftypes.h:40

References i, lzma_index_s::prealloc, and PREALLOC_MAX.

Referenced by index_decode().