]> git.ipfire.org Git - thirdparty/xz.git/commitdiff
liblzma: Add lzma_index_iter_locate_block()
authorLasse Collin <lasse.collin@tukaani.org>
Fri, 23 May 2025 11:38:49 +0000 (14:38 +0300)
committerLasse Collin <lasse.collin@tukaani.org>
Fri, 23 May 2025 11:38:49 +0000 (14:38 +0300)
It locates a Block using the Block number in the .xz file.
The first Block is 1.

Now there are two functions to locate a Block:
  - lzma_index_iter_locate() uses uncompressed offset.
  - lzma_index_iter_locate_block() uses Block number.

src/liblzma/api/lzma/index.h
src/liblzma/common/index.c
src/liblzma/liblzma_generic.map
src/liblzma/liblzma_linux.map

index 8f0aa714551945a883dbcfbffd12791a21ad0731..d96239384b869de8edc1806d5c1dbcd48b81294d 100644 (file)
@@ -662,6 +662,38 @@ extern LZMA_API(lzma_bool) lzma_index_iter_locate(
                lzma_index_iter *iter, lzma_vli target_offset) lzma_nothrow;
 
 
+/**
+ * \brief       Locate a Block by Block number
+ *
+ * If target_block is non-zero and doesn't exceed the number of Blocks in
+ * the lzma_index (the value returned by lzma_index_block_count()):
+ *  - Information about the Stream and Block containing the requested
+ *    Block is stored into *iter. iter->block.number_in_file will equal
+ *    target_block.
+ *  - Internal state of the iterator is adjusted so that
+ *    lzma_index_iter_next() can be used to read subsequent Blocks or Streams.
+ *
+ * If target_block is zero or greater than the number of Blocks in the
+ * lzma_index, *iter is not modified.
+ *
+ * \param       iter    Iterator that was earlier initialized with
+ *                      lzma_index_iter_init().
+ * \param       target_block
+ *                      Block number which the caller would like to locate
+ *                      from the Stream. The first Block is 1.
+ *
+ * \return      lzma_bool:
+ *              - true if target_block is zero or greater than the number of
+ *                Blocks in the Index (failure)
+ *              - false if target_block > 0 and
+ *                target_block <= lzma_index_block_count() (success)
+ *
+ * \since       5.9.1alpha
+ */
+extern LZMA_API(lzma_bool) lzma_index_iter_locate_block(
+               lzma_index_iter *iter, lzma_vli target_block) lzma_nothrow;
+
+
 /**
  * \brief       Concatenate lzma_indexes
  *
index afef5374888f1d4ae3ac5e2429c7a6db3c4d31ef..34002cb05acc86d3ac3bb23ab57587492dc6a290 100644 (file)
@@ -1267,3 +1267,68 @@ lzma_index_iter_locate(lzma_index_iter *iter, lzma_vli target)
 
        return false;
 }
+
+
+extern LZMA_API(lzma_bool)
+lzma_index_iter_locate_block(lzma_index_iter *iter, lzma_vli target_block)
+{
+       const lzma_index *i = iter->internal[ITER_INDEX].p;
+
+       // Block numbering starts from one, so return immediately if
+       // Block zero was requested. Also return if the Block number
+       // exceeds the number of Records/Blocks we have.
+       if (target_block == 0 || i->record_count < target_block)
+               return true;
+
+       // Find the Stream that contains the target Block.
+       const index_stream *stream = NULL;
+       {
+               const index_stream *s = (const index_stream *)i->streams.root;
+               while (s != NULL) {
+                       // s->block_number_base tells how many Blocks there
+                       // are before the Stream, and Block numbering starts
+                       // from one, so >= is correct.
+                       if (s->block_number_base >= target_block) {
+                               s = (const index_stream *)s->node.left;
+                       } else {
+                               stream = s;
+                               s = (const index_stream *)s->node.right;
+                       }
+               }
+       }
+
+       // A Stream must have been found because we checked that
+       // target_block doesn't exceed the number of Records.
+       assert(stream != NULL);
+
+       // Find the Record group from the Stream.
+       const index_group *group = NULL;
+       {
+               const index_group *g
+                               = (const index_group *)stream->groups.root;
+               while (g != NULL) {
+                       // g->number_base tells the Block number of the first
+                       // Record in the group, and Block numbering starts
+                       // from one, so > is correct.
+                       if (g->number_base > target_block) {
+                               g = (const index_group *)g->node.left;
+                       } else {
+                               group = g;
+                               g = (const index_group *)g->node.right;
+                       }
+               }
+       }
+
+       // The correct group must have been found.
+       assert(group != NULL);
+       assert(group->number_base <= target_block);
+       assert(group->number_base + group->last >= target_block);
+
+       iter->internal[ITER_STREAM].p = stream;
+       iter->internal[ITER_GROUP].p = group;
+       iter->internal[ITER_RECORD].s = target_block - group->number_base;
+
+       iter_set_info(iter);
+
+       return false;
+}
index 2bef27a8f7d75c769810c0a5b3338fd556049c9f..b4fcc391b024ce9402964e16d7e7d15ecfc8dd0f 100644 (file)
@@ -136,3 +136,8 @@ global:
        lzma_bcj_x86_encode;
        lzma_bcj_x86_decode;
 } XZ_5.6.0;
+
+XZ_5.9.0alpha {
+global:
+       lzma_index_iter_locate_block;
+} XZ_5.8;
index 50f1571de2196680cc2c1e6a46a0a73f38fa6e3b..2aa51db43c3368cab9c5ad037b1ff43d9ac6fe57 100644 (file)
@@ -151,3 +151,8 @@ global:
        lzma_bcj_x86_encode;
        lzma_bcj_x86_decode;
 } XZ_5.6.0;
+
+XZ_5.9.0alpha {
+global:
+       lzma_index_iter_locate_block;
+} XZ_5.8;