libsparse: Add sparse typed callback

Currently, sparse_file_callback uses libsparse's
own logic for reading a file into a buffer. However,
a caller may want to use their own logic for doing
this in order to customize the buffer size and parallelize
the reads/writes. Also, a caller may want to implement
fill blocks with their own logic as well. To do this
add sparse_file_typed_callback which calls a different
callback function depending on the type of the sparse
chunk being written.

Test: Use typed callback for fd writes
Bug: 78793464
Change-Id: I75955a464fc05991f806339830fdfa05fda354b9
diff --git a/libsparse/sparse.cpp b/libsparse/sparse.cpp
index cb288c5..f5ca907 100644
--- a/libsparse/sparse.cpp
+++ b/libsparse/sparse.cpp
@@ -160,7 +160,30 @@
   struct output_file* out;
 
   chunks = sparse_count_chunks(s);
-  out = output_file_open_callback(write, priv, s->block_size, s->len, false, sparse, chunks, crc);
+  out = output_file_open_callback(write, nullptr, nullptr, nullptr, priv, s->block_size, s->len,
+                                  sparse, chunks, crc);
+
+  if (!out) return -ENOMEM;
+
+  ret = write_all_blocks(s, out);
+
+  output_file_close(out);
+
+  return ret;
+}
+
+int sparse_file_callback_typed(struct sparse_file* s, bool sparse,
+                               int (*data_write)(void* priv, const void* data, size_t len),
+                               int (*fd_write)(void* priv, int fd, size_t len),
+                               int (*fill_write)(void* priv, uint32_t fill_val, size_t len),
+                               int (*skip_write)(void* priv, int64_t len), void* priv) {
+  int ret;
+  int chunks;
+  struct output_file* out;
+
+  chunks = sparse_count_chunks(s);
+  out = output_file_open_callback(data_write, fd_write, fill_write, skip_write, priv, s->block_size,
+                                  s->len, sparse, chunks, false);
 
   if (!out) return -ENOMEM;
 
@@ -198,8 +221,8 @@
   chk.write = write;
   chk.block = chk.nr_blocks = 0;
   chunks = sparse_count_chunks(s);
-  out = output_file_open_callback(foreach_chunk_write, &chk, s->block_size, s->len, false, sparse,
-                                  chunks, crc);
+  out = output_file_open_callback(foreach_chunk_write, nullptr, nullptr, nullptr, &chk,
+                                  s->block_size, s->len, sparse, chunks, crc);
 
   if (!out) return -ENOMEM;
 
@@ -227,8 +250,8 @@
   int64_t count = 0;
   struct output_file* out;
 
-  out = output_file_open_callback(out_counter_write, &count, s->block_size, s->len, false, sparse,
-                                  chunks, crc);
+  out = output_file_open_callback(out_counter_write, nullptr, nullptr, nullptr, &count,
+                                  s->block_size, s->len, sparse, chunks, crc);
   if (!out) {
     return -1;
   }
@@ -267,8 +290,8 @@
   len -= overhead;
 
   start = backed_block_iter_new(from->backed_block_list);
-  out_counter = output_file_open_callback(out_counter_write, &count, to->block_size, to->len, false,
-                                          true, 0, false);
+  out_counter = output_file_open_callback(out_counter_write, nullptr, nullptr, nullptr, &count,
+                                          to->block_size, to->len, true, 0, false);
   if (!out_counter) {
     return nullptr;
   }