Deprivatize RBuffer ##util
Some checks failed
build / linux-wasi (push) Has been cancelled
build / linux-wasi-api (push) Has been cancelled
build / linux-csnext (push) Has been cancelled
build / linux-ssl-crypto (push) Has been cancelled
build / tarball (push) Has been cancelled
build / linux-static (push) Has been cancelled
build / linux-acr-rpm-64 (push) Has been cancelled
build / linux-acr-deb (amd64) (push) Has been cancelled
build / linux-acr-deb (arm64, aarch64-linux-gnu) (push) Has been cancelled
build / linux-acr-deb (i386, multilib) (push) Has been cancelled
build / macos-acr (arm64, 13) (push) Has been cancelled
build / macos-acr (x86_64, 12) (push) Has been cancelled
build / ios (cydia32) (push) Has been cancelled
build / ios (true, cydia) (push) Has been cancelled
build / android-acr (16, arm) (push) Has been cancelled
build / android-acr (aarch64) (push) Has been cancelled
build / android-meson (x86_64) (push) Has been cancelled
build / w32-meson (push) Has been cancelled
build / w64-static-2022 (push) Has been cancelled
build / w64-static (push) Has been cancelled
build / w64-meson (push) Has been cancelled
CI / linux-acr-oldlibsbug (push) Has been cancelled
CI / linux-nocs (push) Has been cancelled
CI / linux-acr-gperf (push) Has been cancelled
CI / linux-sys-capstone (push) Has been cancelled
CI / linux-acr-resymlink (push) Has been cancelled
CI / linux-test (push) Has been cancelled
CI / linux-static-meson (push) Has been cancelled
CI / macos-test (push) Has been cancelled
CI / linux-rpath (push) Has been cancelled
CI / macos-rpath (push) Has been cancelled
CI / linux-meson-spaces (push) Has been cancelled
CI / linux-tinyasan-fuzz (push) Has been cancelled
CI / linux-asan-fuzz (push) Has been cancelled
CI / w64-make (push) Has been cancelled
CI / w32-mingw (push) Has been cancelled
CI / w64-mingw (push) Has been cancelled
Code scanning - action / CodeQL-Build (push) Has been cancelled
Coverity Scan / latest (push) Has been cancelled
tcc / ubuntu-tcc-newabi (push) Has been cancelled
tcc / ubuntu-tcc-test (push) Has been cancelled
tcc / ubuntu-tcc-nodbg (push) Has been cancelled
tcc / r2pm-tcc (push) Has been cancelled
tcc / ubuntu-tcc-syslibs (push) Has been cancelled
build / check_abi_compatibility (push) Has been cancelled
build / check_release (push) Has been cancelled
build / release (push) Has been cancelled

This commit is contained in:
condret 2024-11-19 22:31:19 +01:00
parent 4eb49d5ad8
commit 846a33980f
10 changed files with 341 additions and 445 deletions

View File

@ -1,6 +1,7 @@
#ifndef R_BUF_H
#define R_BUF_H
#include <r_util/r_mem.h>
//#include <r_io.h>
#ifdef __cplusplus
extern "C" {
@ -38,7 +39,6 @@ typedef struct r_buffer_methods_t {
RBufferNonEmptyList nonempty_list;
} RBufferMethods;
#if R2_USE_NEW_ABI
typedef enum {
R_BUFFER_FILE,
R_BUFFER_IO,
@ -48,30 +48,79 @@ typedef enum {
R_BUFFER_REF,
R_BUFFER_CACHE,
} RBufferType;
#endif
struct r_buf_t {
const RBufferMethods *methods;
void *priv;
ut8 *whole_buf;
bool readonly;
ut8 Oxff_priv;
int refctr;
// R2_600 R_REF_TYPE instead of refcnt;
#if R2_USE_NEW_ABI
RBufferType type;
#endif
};
typedef struct r_buf_file_t {
int fd;
ut8 tmp[8];
} RBufferFile;
// XXX: this should not be public
typedef struct r_buf_cache_t {
typedef struct r_buf_io_t {
struct r_io_bind_t *iob;
int fd;
} RBufferIO;
typedef struct r_buf_bytes_t {
ut8 *buf;
ut64 length;
ut64 offset;
bool is_bufowner;
} RBufferBytes;
typedef struct r_buf_mmap_t {
// NOTE: this needs to be first, so that bytes operations will work without changes
RBufferBytes bytes;
RMmap *mmap;
} RBufferMmap;
typedef struct r_buf_sparse_item_t {
ut64 from;
ut64 to;
int size;
ut8 *data;
int written;
} RBufferSparseItem;
typedef struct r_buf_sparse_t {
RList *sparse;
ut64 offset;
} RBufferSparse;
typedef struct r_buf_ref_t {
RBuffer *parent;
ut64 cur;
ut64 base;
ut64 size;
} RBufferRef;
typedef struct r_buf_cache_t {
// init
RBuffer *sb; // source/parent buffer
bool is_bufowner;
ut64 length;
// internal
struct r_io_cache_layer_t *cl;
ut64 offset;
ut8 *buf;
} RBufferCache;
struct r_buf_t {
const RBufferMethods *methods;
union {
RBufferFile *rb_file;
RBufferIO *rb_io;
RBufferBytes *rb_bytes;
RBufferMmap *rb_mmap;
RBufferSparse *rb_sparse;
RBufferRef *rb_ref;
RBufferCache *rb_cache;
};
ut8 *whole_buf;
bool readonly;
ut8 Oxff_priv;
int refctr;
RBufferType type;
};
/* constructors */
R_API RBuffer *r_buf_new(void);
R_API RBuffer *r_buf_new_with_io(void *iob, int fd);
@ -85,10 +134,8 @@ R_API RBuffer *r_buf_new_slice(RBuffer *b, ut64 offset, ut64 size);
R_API RBuffer *r_buf_new_empty(ut64 len);
R_API RBuffer *r_buf_new_mmap(const char *file, int flags);
R_API RBuffer *r_buf_new_sparse(ut8 Oxff);
#if R2_USE_NEW_ABI
R_API char *r_buf_describe(RBuffer *b);
R_API RBuffer *r_buf_new_with_cache(RBuffer *b, bool steal);
#endif
/* methods */
R_API bool r_buf_dump(RBuffer *buf, const char *file);

View File

@ -121,7 +121,7 @@ static int fwblock(FILE *fd, ut8 *b, ut32 start_addr, ut16 size) {
}
static int __write(RIO *io, RIODesc *fd, const ut8 *buf, int count) {
RBufferSparse *rbs;
RBufferSparseItem *rbsi;
RListIter *iter;
if (!fd || !fd->data || (fd->perm & R_PERM_W) == 0 || count <= 0) {
@ -146,12 +146,12 @@ static int __write(RIO *io, RIODesc *fd, const ut8 *buf, int count) {
/* disk write : process each sparse chunk */
// TODO: sort addresses + check overlap?
RList *nonempty = r_buf_nonempty_list (rih->rbuf);
r_list_foreach (nonempty, iter, rbs) {
ut16 addl0 = rbs->from & 0xffff;
ut16 addh0 = rbs->from >> 16;
ut16 addh1 = rbs->to >> 16;
r_list_foreach (nonempty, iter, rbsi) {
ut16 addl0 = rbsi->from & 0xffff;
ut16 addh0 = rbsi->from >> 16;
ut16 addh1 = rbsi->to >> 16;
ut16 tsiz = 0;
if (rbs->size == 0) {
if (rbsi->size == 0) {
continue;
}
@ -167,7 +167,7 @@ static int __write(RIO *io, RIODesc *fd, const ut8 *buf, int count) {
// 00 records (data)
tsiz = -addl0;
addl0 = 0;
if (fwblock (out, rbs->data, rbs->from, tsiz)) {
if (fwblock (out, rbsi->data, rbsi->from, tsiz)) {
R_LOG_ERROR ("ihex:fwblock error");
r_list_free (nonempty);
fclose (out);
@ -182,7 +182,7 @@ static int __write(RIO *io, RIODesc *fd, const ut8 *buf, int count) {
return -1;
}
// 00 records (remaining data)
if (fwblock (out, rbs->data + tsiz, (addh1 << 16) | addl0, rbs->size - tsiz)) {
if (fwblock (out, rbsi->data + tsiz, (addh1 << 16) | addl0, rbsi->size - tsiz)) {
R_LOG_ERROR ("ihex:fwblock error");
r_list_free (nonempty);
fclose (out);

View File

@ -4,27 +4,13 @@
#include <r_util.h>
#include <r_io.h>
#if !R2_USE_NEW_ABI
typedef enum {
R_BUFFER_FILE,
R_BUFFER_IO,
R_BUFFER_BYTES,
R_BUFFER_MMAP,
R_BUFFER_SPARSE,
R_BUFFER_REF,
} RBufferType;
#endif
#include "buf_file.c"
#include "buf_sparse.c"
#include "buf_bytes.c"
#include "buf_mmap.c"
#include "buf_io.c"
#include "buf_ref.c"
#if R2_USE_NEW_ABI
#include "buf_cache.c"
#endif
static bool buf_init(RBuffer *b, const void *user) {
R_RETURN_VAL_IF_FAIL (b && b->methods, false);
@ -114,11 +100,9 @@ static RBuffer *new_buffer(RBufferType type, const void *user) {
case R_BUFFER_MMAP:
b->methods = &buffer_mmap_methods;
break;
#if R2_USE_NEW_ABI
case R_BUFFER_CACHE:
b->methods = &buffer_cache_methods;
break;
#endif
case R_BUFFER_SPARSE:
b->methods = &buffer_sparse_methods;
break;
@ -149,17 +133,12 @@ static RBuffer *new_buffer(RBufferType type, const void *user) {
// ret # of bytes copied
R_API RBuffer *r_buf_new_with_io(void *iob, int fd) {
R_RETURN_VAL_IF_FAIL (iob && fd >= 0, NULL);
struct buf_io_user u = {0};
u.iob = (RIOBind *)iob;
u.fd = fd;
RBufferIO u = {(RIOBind *)iob, fd};
return new_buffer (R_BUFFER_IO, &u);
}
R_API RBuffer *r_buf_new_with_pointers(const ut8 *bytes, ut64 len, bool steal) {
struct buf_bytes_user u = {0};
u.data_steal = bytes;
u.length = len;
u.steal = steal;
struct buf_bytes_user u = {.data_steal = bytes, .length = len, .steal = steal};
return new_buffer (R_BUFFER_BYTES, &u);
}
@ -169,10 +148,7 @@ R_API RBuffer *r_buf_new_empty(ut64 len) {
return NULL;
}
struct buf_bytes_user u = {0};
u.data_steal = buf;
u.length = len;
u.steal = true;
struct buf_bytes_user u = {.data_steal = buf, .length = len, .steal = true};
RBuffer *res = new_buffer (R_BUFFER_BYTES, &u);
if (!res) {
free (buf);
@ -181,17 +157,12 @@ R_API RBuffer *r_buf_new_empty(ut64 len) {
}
R_API RBuffer *r_buf_new_with_bytes(const ut8 *bytes, ut64 len) {
struct buf_bytes_user u = {0};
u.data = bytes;
u.length = len;
struct buf_bytes_user u = {.data = bytes, .length = len};
return new_buffer (R_BUFFER_BYTES, &u);
}
R_API RBuffer *r_buf_new_slice(RBuffer *b, ut64 offset, ut64 size) {
struct buf_ref_user u = {0};
u.parent = b;
u.offset = offset;
u.size = size;
struct buf_ref_user u = {b, offset, size};
return new_buffer (R_BUFFER_REF, &u);
}
@ -213,23 +184,15 @@ R_API RBuffer *r_buf_new_sparse(ut8 Oxff) {
return b;
}
#if R2_USE_NEW_ABI
R_API RBuffer *r_buf_new_with_cache(RBuffer *sb, bool steal) {
RBuffer *b = new_buffer (R_BUFFER_CACHE, NULL);
if (b) {
struct minicachebuf {
RBuffer *sb;
bool owned;
ut64 length;
};
struct minicachebuf *mcb = b->priv;
mcb->sb = sb;
mcb->owned = steal;
mcb->length = r_buf_size (sb);
b->rb_cache->sb = sb;
b->rb_cache->is_bufowner = steal;
b->rb_cache->length = r_buf_size (sb);
}
return b;
}
#endif
R_API RBuffer *r_buf_new(void) {
struct buf_bytes_user u = {0};
@ -252,17 +215,12 @@ R_API ut64 r_buf_size(RBuffer *b) {
// rename to new?
R_API RBuffer *r_buf_new_mmap(const char *filename, int perm) {
R_RETURN_VAL_IF_FAIL (filename, NULL);
struct buf_mmap_user u = {0};
u.filename = filename;
u.perm = perm;
struct buf_mmap_user u = {filename, perm};
return new_buffer (R_BUFFER_MMAP, &u);
}
R_API RBuffer *r_buf_new_file(const char *file, int perm, int mode) {
struct buf_file_user u = {0};
u.file = file;
u.perm = perm;
u.mode = mode;
struct buf_file_user u = {file, perm, mode};
return new_buffer (R_BUFFER_FILE, &u);
}
@ -808,7 +766,6 @@ R_API st64 r_buf_sleb128(RBuffer *b, st64 *v) {
return offset / 7;
}
#if R2_USE_NEW_ABI
R_API char *r_buf_describe(RBuffer *b) {
const char *type = "unknown";
switch (b->type) {
@ -836,4 +793,3 @@ R_API char *r_buf_describe(RBuffer *b) {
}
return r_str_newf ("RBuffer<%s>(.%s) @ %p", type, b->readonly? "ro": "rw", b);
}
#endif

View File

@ -9,123 +9,109 @@ struct buf_bytes_user {
bool steal;
};
struct buf_bytes_priv {
ut8 *buf;
ut64 length;
ut64 offset;
bool is_bufowner;
};
static inline struct buf_bytes_priv *get_priv_bytes(RBuffer *b) {
struct buf_bytes_priv *priv = (struct buf_bytes_priv *)b->priv;
r_warn_if_fail (priv);
return priv;
}
static bool buf_bytes_init(RBuffer *b, const void *user) {
const struct buf_bytes_user *u = (const struct buf_bytes_user *)user;
struct buf_bytes_priv *priv = R_NEW0 (struct buf_bytes_priv);
if (!priv) {
const struct buf_bytes_user *u = user;
b->rb_bytes = R_NEW0 (RBufferBytes);
if (!b->rb_bytes) {
return false;
}
priv->offset = 0;
priv->length = u->length;
b->rb_bytes->offset = 0;
b->rb_bytes->length = u->length;
if (u->data_steal) {
priv->buf = (ut8 *)u->data_steal;
priv->is_bufowner = u->steal;
b->rb_bytes->buf = (ut8 *)u->data_steal;
b->rb_bytes->is_bufowner = u->steal;
} else {
#if 0
size_t length = priv->length > 0? priv->length: 1;
priv->buf = malloc (length);
if (!priv->buf) {
free (priv);
size_t length = b->rb_bytes->length > 0? b->rb_bytes->length: 1;
b->rb_bytes->buf = malloc (length);
if (!b->rb_bytes->buf) {
free (b->rb_bytes);
return false;
}
if (priv->length > 0) {
memmove (priv->buf, u->data, priv->length);
if (b->rb_bytes->length > 0) {
memmove (b->rb_bytes->buf, u->data, b->rb_bytes->length);
}
#else
if (priv->length > 0) {
priv->buf = malloc (priv->length);
if (!priv->buf) {
free (priv);
if (b->rb_bytes->length > 0) {
b->rb_bytes->buf = malloc (b->rb_bytes->length);
if (!b->rb_bytes->buf) {
free (b->rb_bytes);
return false;
}
memmove (priv->buf, u->data, priv->length);
memmove (b->rb_bytes->buf, u->data, b->rb_bytes->length);
}
#endif
priv->is_bufowner = true;
b->rb_bytes->is_bufowner = true;
}
b->priv = priv;
return true;
}
static bool buf_bytes_fini(RBuffer *b) {
struct buf_bytes_priv *priv = get_priv_bytes (b);
if (priv->is_bufowner) {
free (priv->buf);
r_warn_if_fail (b->rb_bytes);
if (b->rb_bytes->is_bufowner) {
free (b->rb_bytes->buf);
}
R_FREE (b->priv);
R_FREE (b->rb_bytes);
return true;
}
static bool buf_bytes_resize(RBuffer *b, ut64 newsize) {
struct buf_bytes_priv *priv = get_priv_bytes (b);
if (newsize > priv->length) {
ut8 *t = realloc (priv->buf, newsize);
r_warn_if_fail (b->rb_bytes);
if (newsize > b->rb_bytes->length) {
ut8 *t = realloc (b->rb_bytes->buf, newsize);
if (!t) {
return false;
}
priv->buf = t;
memset (priv->buf + priv->length, b->Oxff_priv, newsize - priv->length);
b->rb_bytes->buf = t;
memset (b->rb_bytes->buf + b->rb_bytes->length, b->Oxff_priv, newsize - b->rb_bytes->length);
}
priv->length = newsize;
b->rb_bytes->length = newsize;
return true;
}
static st64 buf_bytes_read(RBuffer *b, ut8 *buf, ut64 len) {
struct buf_bytes_priv *priv = get_priv_bytes (b);
if (!priv->buf) {
r_warn_if_fail (b->rb_bytes);
if (!b->rb_bytes->buf) {
return 0;
}
ut64 real_len = priv->length < priv->offset? 0: R_MIN (priv->length - priv->offset, len);
// memmove (buf, priv->buf + priv->offset, real_len);
memcpy (buf, priv->buf + priv->offset, real_len);
priv->offset += real_len;
ut64 real_len = b->rb_bytes->length < b->rb_bytes->offset? 0: R_MIN (b->rb_bytes->length - b->rb_bytes->offset, len);
// memmove (buf, b->rb_bytes->buf + b->rb_bytes->offset, real_len);
memcpy (buf, b->rb_bytes->buf + b->rb_bytes->offset, real_len);
b->rb_bytes->offset += real_len;
return real_len;
}
static st64 buf_bytes_write(RBuffer *b, const ut8 *buf, ut64 len) {
struct buf_bytes_priv *priv = get_priv_bytes (b);
if (priv->offset > priv->length || priv->offset + len >= priv->length) {
bool r = r_buf_resize (b, priv->offset + len);
r_warn_if_fail (b->rb_bytes);
if (b->rb_bytes->offset > b->rb_bytes->length || b->rb_bytes->offset + len >= b->rb_bytes->length) {
bool r = r_buf_resize (b, b->rb_bytes->offset + len);
if (!r) {
return -1;
}
}
memmove (priv->buf + priv->offset, buf, len);
priv->offset += len;
memmove (b->rb_bytes->buf + b->rb_bytes->offset, buf, len);
b->rb_bytes->offset += len;
return len;
}
static ut64 buf_bytes_get_size(RBuffer *b) {
struct buf_bytes_priv *priv = get_priv_bytes (b);
return priv->length;
r_warn_if_fail (b->rb_bytes);
return b->rb_bytes->length;
}
static st64 buf_bytes_seek(RBuffer *b, st64 addr, int whence) {
struct buf_bytes_priv *priv = get_priv_bytes (b);
r_warn_if_fail (b->rb_bytes);
if (R_UNLIKELY (addr < 0)) {
if (addr > -UT48_MAX) {
if (-addr > (st64)priv->offset) {
if (-addr > (st64)b->rb_bytes->offset) {
return -1;
}
} else {
return -1;
}
}
ut64 po = priv->offset;
ut64 po = b->rb_bytes->offset;
if (R_LIKELY (whence == R_BUF_SET)) {
// 50%
po = addr;
@ -134,18 +120,18 @@ static st64 buf_bytes_seek(RBuffer *b, st64 addr, int whence) {
po += addr;
} else {
// 5%
po = priv->length + addr;
po = b->rb_bytes->length + addr;
}
priv->offset = po;
b->rb_bytes->offset = po;
return po;
}
static ut8 *buf_bytes_get_whole_buf(RBuffer *b, ut64 *sz) {
struct buf_bytes_priv *priv = get_priv_bytes (b);
r_warn_if_fail (b->rb_bytes);
if (sz) {
*sz = priv->length;
*sz = b->rb_bytes->length;
}
return priv->buf;
return b->rb_bytes->buf;
}
static const RBufferMethods buffer_bytes_methods = {

View File

@ -1,28 +1,10 @@
/* radare2 - LGPL - Copyright 2024 - pancake */
#include <r_util.h>
#if R2_USE_NEW_ABI
typedef struct buf_cache_priv {
// init
RBuffer *sb; // source/parent buffer
bool is_bufowner;
ut64 length;
// internal
RIOCacheLayer *cl;
ut64 offset;
ut8 *buf;
} RBufCache;
static inline RBufCache *get_priv_cache_bytes(RBuffer *b) {
RBufCache *priv = (RBufCache*)b->priv;
r_warn_if_fail (priv);
return priv;
}
#include <r_io.h>
static void iocache_item_free(void *data) {
RIOCacheItem *ci = (RIOCacheItem *)data;
RIOCacheItem *ci = data;
if (ci) {
free (ci->tree_itv);
free (ci->data);
@ -94,8 +76,8 @@ static st64 buf_cache_seek(RBuffer *b, st64 addr, int whence);
static st64 buf_cache_read(RBuffer *b, ut8 *buf, ut64 len) {
R_RETURN_VAL_IF_FAIL (b && buf && (len > 0), false);
RBufCache *priv = get_priv_cache_bytes (b);
ut64 addr = priv->offset;
r_warn_if_fail (b->rb_cache);
ut64 addr = b->rb_cache->offset;
if ((UT64_MAX - len + 1) < addr) {
st64 ret = buf_cache_read (b, buf, UT64_MAX - addr + 1);
len = len - (UT64_MAX - addr + 1);
@ -103,8 +85,8 @@ static st64 buf_cache_read(RBuffer *b, ut8 *buf, ut64 len) {
return ret + buf_cache_read (b, &buf[UT64_MAX - addr + 1], len);
}
RInterval itv = (RInterval){addr, len};
r_buf_read_at (priv->sb, addr, buf, len);
RIOCacheLayer *layer = priv->cl; // r_list_last (io->cache.layers);
r_buf_read_at (b->rb_cache->sb, addr, buf, len);
RIOCacheLayer *layer = b->rb_cache->cl; // r_list_last (io->cache.layers);
RRBNode *node = _find_entry_ci_node (layer->tree, &itv);
if (!node) {
return len;
@ -152,8 +134,8 @@ static int _ci_start_cmp_cb(void *incoming, void *in, void *user) {
static st64 buf_cache_write(RBuffer *b, const ut8 *buf, ut64 len) {
R_RETURN_VAL_IF_FAIL (b && buf && (len > 0), 0);
RBufCache *priv = get_priv_cache_bytes (b);
ut64 addr = priv->offset;
r_warn_if_fail (b->rb_cache);
ut64 addr = b->rb_cache->offset;
if ((UT64_MAX - len + 1) < addr) {
st64 ret = buf_cache_write (b, buf, UT64_MAX - addr + 1);
@ -166,10 +148,10 @@ static st64 buf_cache_write(RBuffer *b, const ut8 *buf, ut64 len) {
if (!ci) {
return false;
}
r_buf_read_at (priv->sb, addr, ci->odata, len);
r_buf_read_at (b->rb_cache->sb, addr, ci->odata, len);
// (void)r_io_read_at (io, addr, ci->odata, len); // ignore failed reads?
memcpy (ci->data, buf, len);
RIOCacheLayer *layer = priv->cl; // r_list_last (io->cache.layers);
RIOCacheLayer *layer = b->rb_cache->cl; // r_list_last (io->cache.layers);
RRBNode *node = _find_entry_ci_node (layer->tree, &itv);
if (node) {
RIOCacheItem *_ci = (RIOCacheItem *)node->data;
@ -198,48 +180,44 @@ static st64 buf_cache_write(RBuffer *b, const ut8 *buf, ut64 len) {
static bool buf_cache_init(RBuffer *b, const void *user) {
// TODO take sb and owned from user instead of setting it in with_cache() after init
RBufCache *priv = R_NEW0 (RBufCache);
if (!priv) {
b->rb_cache = R_NEW0 (RBufferCache);
if (!b->rb_cache) {
return false;
}
priv->cl = iocache_layer_new ();
priv->length = 0;
priv->offset = 0;
priv->is_bufowner = false;
b->priv = priv;
b->rb_cache->cl = iocache_layer_new ();
return true;
}
static bool buf_cache_fini(RBuffer *b) {
RBufCache *priv = get_priv_cache_bytes (b);
if (priv->is_bufowner) {
r_buf_free (priv->sb);
r_warn_if_fail (b->rb_cache);
if (b->rb_cache->is_bufowner) {
r_buf_free (b->rb_cache->sb);
}
iocache_layer_free (priv->cl);
R_FREE (priv->buf);
R_FREE (b->priv);
iocache_layer_free (b->rb_cache->cl);
R_FREE (b->rb_cache->buf);
R_FREE (b->rb_cache);
return true;
}
static bool buf_cache_resize(RBuffer *b, ut64 newsize) {
RBufCache *priv = get_priv_cache_bytes (b);
if (newsize > priv->length) {
r_warn_if_fail (b->rb_cache);
if (newsize > b->rb_cache->length) {
r_buf_resize (b, newsize);
}
priv->length = newsize;
b->rb_cache->length = newsize;
return true;
}
static ut64 buf_cache_get_size(RBuffer *b) {
RBufCache *priv = get_priv_cache_bytes (b);
return priv->length;
r_warn_if_fail (b->rb_cache);
return b->rb_cache->length;
}
static st64 buf_cache_seek(RBuffer *b, st64 addr, int whence) {
RBufCache *priv = get_priv_cache_bytes (b);
r_warn_if_fail (b->rb_cache);
if (addr < 0) {
if (addr > -UT48_MAX) {
if (-addr > (st64)priv->offset) {
if (-addr > (st64)b->rb_cache->offset) {
return -1;
}
} else {
@ -248,31 +226,31 @@ static st64 buf_cache_seek(RBuffer *b, st64 addr, int whence) {
}
if (R_LIKELY (whence == R_BUF_SET)) {
// 50%
priv->offset = addr;
b->rb_cache->offset = addr;
} else if (whence == R_BUF_CUR) {
// 20%
priv->offset += addr;
b->rb_cache->offset += addr;
} else {
// 5%
priv->offset = priv->length + addr;
b->rb_cache->offset = b->rb_cache->length + addr;
}
return priv->offset;
return b->rb_cache->offset;
}
static ut8 *buf_cache_get_whole_buf(RBuffer *b, ut64 *sz) {
RBufCache *priv = get_priv_cache_bytes (b);
r_warn_if_fail (b->rb_cache);
if (sz) {
*sz = priv->length;
*sz = b->rb_cache->length;
}
if (priv->buf) {
R_FREE (priv->buf);
if (b->rb_cache->buf) {
R_FREE (b->rb_cache->buf);
}
ut8 *nbuf = malloc (priv->length);
ut8 *nbuf = malloc (b->rb_cache->length);
if (nbuf) {
r_buf_read_at (b, 0, nbuf, priv->length);
priv->buf = nbuf;
r_buf_read_at (b, 0, nbuf, b->rb_cache->length);
b->rb_cache->buf = nbuf;
}
return priv->buf;
return b->rb_cache->buf;
}
static const RBufferMethods buffer_cache_methods = {
@ -285,4 +263,3 @@ static const RBufferMethods buffer_cache_methods = {
.seek = buf_cache_seek,
.get_whole_buf = buf_cache_get_whole_buf
};
#endif

View File

@ -9,71 +9,58 @@ struct buf_file_user {
int mode;
};
struct buf_file_priv {
int fd;
ut8 tmp[8];
};
static inline struct buf_file_priv *get_priv_file(RBuffer *b) {
struct buf_file_priv *priv = (struct buf_file_priv *)b->priv;
r_warn_if_fail (priv);
return priv;
}
static bool buf_file_init(RBuffer *b, const void *user) {
const struct buf_file_user *u = (const struct buf_file_user *)user;
struct buf_file_priv *priv = R_NEW0 (struct buf_file_priv);
if (!priv) {
const struct buf_file_user *u = user;
b->rb_file = R_NEW0 (RBufferFile);
if (!b->rb_file) {
return false;
}
int fd = r_sandbox_open (u->file, u->perm, u->mode);
if (fd == -1) {
free (priv);
b->rb_file->fd = r_sandbox_open (u->file, u->perm, u->mode);
if (b->rb_file->fd == -1) {
free (b->rb_file);
return false;
}
priv->fd = fd;
b->priv = priv;
return true;
}
static bool buf_file_fini(RBuffer *b) {
struct buf_file_priv *priv = get_priv_file (b);
r_sandbox_close (priv->fd);
R_FREE (b->priv);
r_warn_if_fail (b->rb_file);
r_sandbox_close (b->rb_file->fd);
R_FREE (b->rb_file);
return true;
}
static ut64 buf_file_get_size(RBuffer *b) {
struct buf_file_priv *priv = get_priv_file (b);
int pos = r_sandbox_lseek (priv->fd, 0, SEEK_CUR);
int res = r_sandbox_lseek (priv->fd, 0, SEEK_END);
r_sandbox_lseek (priv->fd, pos, SEEK_SET);
r_warn_if_fail (b->rb_file);
int pos = r_sandbox_lseek (b->rb_file->fd, 0, SEEK_CUR);
int res = r_sandbox_lseek (b->rb_file->fd, 0, SEEK_END);
r_sandbox_lseek (b->rb_file->fd, pos, SEEK_SET);
return (ut64)res;
}
static st64 buf_file_read(RBuffer *b, ut8 *buf, ut64 len) {
struct buf_file_priv *priv = get_priv_file (b);
return r_sandbox_read (priv->fd, buf, len);
r_warn_if_fail (b->rb_file);
return r_sandbox_read (b->rb_file->fd, buf, len);
}
static st64 buf_file_write(RBuffer *b, const ut8 *buf, ut64 len) {
struct buf_file_priv *priv = get_priv_file (b);
return r_sandbox_write (priv->fd, buf, len);
r_warn_if_fail (b->rb_file);
return r_sandbox_write (b->rb_file->fd, buf, len);
}
static st64 buf_file_seek(RBuffer *b, st64 addr, int whence) {
struct buf_file_priv *priv = get_priv_file (b);
r_warn_if_fail (b->rb_file);
switch (whence) {
case R_BUF_CUR: whence = SEEK_CUR; break;
case R_BUF_SET: whence = SEEK_SET; break;
case R_BUF_END: whence = SEEK_END; break;
}
return r_sandbox_lseek (priv->fd, addr, whence);
return r_sandbox_lseek (b->rb_file->fd, addr, whence);
}
static bool buf_file_resize(RBuffer *b, ut64 newsize) {
struct buf_file_priv *priv = get_priv_file (b);
return r_sandbox_truncate (priv->fd, newsize) >= 0;
r_warn_if_fail (b->rb_file);
return r_sandbox_truncate (b->rb_file->fd, newsize) >= 0;
}
static const RBufferMethods buffer_file_methods = {

View File

@ -3,44 +3,25 @@
#include <r_util.h>
#include <r_io.h>
struct buf_io_user {
RIOBind *iob;
int fd;
};
struct buf_io_priv {
RIOBind *iob;
int fd;
};
static inline struct buf_io_priv *get_priv_io(RBuffer *b) {
struct buf_io_priv *priv = (struct buf_io_priv *)b->priv;
r_warn_if_fail (priv);
return priv;
}
static bool buf_io_init(RBuffer *b, const void *user) {
const struct buf_io_user *u = (const struct buf_io_user *)user;
struct buf_io_priv *priv = R_NEW0 (struct buf_io_priv);
if (!priv) {
const RBufferIO *rb_io = user;
b->rb_io = R_NEW (RBufferIO);
if (!b->rb_io) {
return false;
}
priv->iob = u->iob;
priv->fd = u->fd;
b->priv = priv;
b->rb_io[0] = rb_io[0];
return true;
}
static bool buf_io_fini(RBuffer *b) {
//struct buf_io_priv *priv = get_priv_io (b);
R_FREE (b->priv);
R_FREE (b->rb_io);
return true;
}
static st64 buf_io_seek(RBuffer *b, st64 addr, int whence) {
struct buf_io_priv *priv = get_priv_io (b);
int io_whence;
r_warn_if_fail (b->rb_io);
switch (whence) {
default:
r_warn_if_reached ();
@ -54,27 +35,27 @@ static st64 buf_io_seek(RBuffer *b, st64 addr, int whence) {
io_whence = R_IO_SEEK_CUR;
break;
}
return priv->iob->fd_seek (priv->iob->io, priv->fd, addr, io_whence);
return b->rb_io->iob->fd_seek (b->rb_io->iob->io, b->rb_io->fd, addr, io_whence);
}
static ut64 buf_io_get_size(RBuffer *b) {
struct buf_io_priv *priv = get_priv_io (b);
return priv->iob->fd_size (priv->iob->io, priv->fd);
r_warn_if_fail (b->rb_io);
return b->rb_io->iob->fd_size (b->rb_io->iob->io, b->rb_io->fd);
}
static bool buf_io_resize(RBuffer *b, ut64 newsize) {
struct buf_io_priv *priv = get_priv_io (b);
return priv->iob->fd_resize (priv->iob->io, priv->fd, newsize);
r_warn_if_fail (b->rb_io);
return b->rb_io->iob->fd_resize (b->rb_io->iob->io, b->rb_io->fd, newsize);
}
static st64 buf_io_read(RBuffer *b, ut8 *buf, ut64 len) {
struct buf_io_priv *priv = get_priv_io (b);
return priv->iob->fd_read (priv->iob->io, priv->fd, buf, len);
r_warn_if_fail (b->rb_io);
return b->rb_io->iob->fd_read (b->rb_io->iob->io, b->rb_io->fd, buf, len);
}
static st64 buf_io_write(RBuffer *b, const ut8 *buf, ut64 len) {
struct buf_io_priv *priv = get_priv_io (b);
return priv->iob->fd_write (priv->iob->io, priv->fd, buf, len);
r_warn_if_fail (b->rb_io);
return b->rb_io->iob->fd_write (b->rb_io->iob->io, b->rb_io->fd, buf, len);
}
static const RBufferMethods buffer_io_methods = {

View File

@ -7,55 +7,41 @@ struct buf_mmap_user {
int perm;
};
// "subclass"" of buf_bytes_priv
struct buf_mmap_priv {
// NOTE: this needs to be first, so that bytes operations will work without changes
struct buf_bytes_priv bytes_priv;
RMmap *mmap;
};
static inline struct buf_mmap_priv *get_priv_mmap(RBuffer *b) {
struct buf_mmap_priv *priv = (struct buf_mmap_priv *)b->priv;
r_warn_if_fail (priv);
return priv;
}
static bool buf_mmap_init(RBuffer *b, const void *user) {
const struct buf_mmap_user *u = (const struct buf_mmap_user *)user;
struct buf_mmap_priv *priv = R_NEW0 (struct buf_mmap_priv);
if (!priv) {
const struct buf_mmap_user *u = user;
b->rb_mmap = R_NEW0 (RBufferMmap);
if (!b->rb_mmap) {
return false;
}
priv->mmap = r_file_mmap (u->filename, u->perm & R_PERM_W, 0);
if (!priv->mmap) {
free (priv);
b->rb_mmap->mmap = r_file_mmap (u->filename, u->perm & R_PERM_W, 0);
if (!b->rb_mmap->mmap) {
free (b->rb_mmap);
return false;
}
priv->bytes_priv.buf = priv->mmap->buf;
priv->bytes_priv.length = priv->mmap->len;
priv->bytes_priv.offset = 0;
b->priv = priv;
b->rb_mmap->bytes.buf = b->rb_mmap->mmap->buf;
b->rb_mmap->bytes.length = b->rb_mmap->mmap->len;
b->rb_mmap->bytes.offset = 0;
return true;
}
static bool buf_mmap_fini(RBuffer *b) {
struct buf_mmap_priv *priv = get_priv_mmap (b);
r_file_mmap_free (priv->mmap);
R_FREE (b->priv);
r_warn_if_fail (b->rb_mmap);
r_file_mmap_free (b->rb_mmap->mmap);
R_FREE (b->rb_mmap);
return true;
}
static bool buf_mmap_resize(RBuffer *b, ut64 newsize) {
struct buf_mmap_priv *priv = get_priv_mmap (b);
if (newsize > priv->mmap->len) {
ut8 *t = r_mem_mmap_resize (priv->mmap, newsize);
r_warn_if_fail (b->rb_mmap);
if (newsize > b->rb_mmap->mmap->len) {
ut8 *t = r_mem_mmap_resize (b->rb_mmap->mmap, newsize);
if (!t) {
return false;
}
priv->bytes_priv.buf = t;
b->rb_mmap->bytes.buf = t;
}
priv->bytes_priv.length = newsize;
b->rb_mmap->bytes.length = newsize;
return true;
}

View File

@ -8,23 +8,10 @@ struct buf_ref_user {
ut64 size;
};
struct buf_ref_priv {
RBuffer *parent;
ut64 cur;
ut64 base;
ut64 size;
};
static inline struct buf_ref_priv *get_priv_ref(RBuffer *b) {
struct buf_ref_priv *priv = (struct buf_ref_priv *)b->priv;
r_warn_if_fail (priv);
return priv;
}
static bool buf_ref_init(RBuffer *b, const void *user) {
const struct buf_ref_user *u = (const struct buf_ref_user *)user;
struct buf_ref_priv *priv = R_NEW0 (struct buf_ref_priv);
if (!priv) {
const struct buf_ref_user *u = user;
b->rb_ref = R_NEW0 (RBufferRef);
if (!b->rb_ref) {
return false;
}
@ -33,63 +20,62 @@ static bool buf_ref_init(RBuffer *b, const void *user) {
// referencer. Copy-on-write? Write to the buffer underneath?
ut64 parent_sz = r_buf_size (u->parent);
b->readonly = true;
priv->parent = r_buf_ref (u->parent);
priv->base = R_MIN (u->offset, parent_sz);
priv->size = R_MIN (parent_sz - priv->base, u->size);
b->priv = priv;
b->rb_ref->parent = r_buf_ref (u->parent);
b->rb_ref->base = R_MIN (u->offset, parent_sz);
b->rb_ref->size = R_MIN (parent_sz - b->rb_ref->base, u->size);
return true;
}
static bool buf_ref_fini(RBuffer *b) {
struct buf_ref_priv *priv = get_priv_ref (b);
r_buf_free (priv->parent);
R_FREE (b->priv);
r_warn_if_fail (b->rb_ref);
r_buf_free (b->rb_ref->parent);
R_FREE (b->rb_ref);
return true;
}
static bool buf_ref_resize(RBuffer *b, ut64 newsize) {
struct buf_ref_priv *priv = get_priv_ref (b);
ut64 parent_sz = r_buf_size (priv->parent);
priv->size = R_MIN (parent_sz - priv->base, newsize);
r_warn_if_fail (b->rb_ref);
const ut64 parent_sz = r_buf_size (b->rb_ref->parent);
b->rb_ref->size = R_MIN (parent_sz - b->rb_ref->base, newsize);
return true;
}
static st64 buf_ref_read(RBuffer *b, ut8 *buf, ut64 len) {
struct buf_ref_priv *priv = get_priv_ref (b);
if (priv->size < priv->cur) {
r_warn_if_fail (b->rb_ref);
if (b->rb_ref->size < b->rb_ref->cur) {
return -1;
}
len = R_MIN (len, priv->size - priv->cur);
st64 r = r_buf_read_at (priv->parent, priv->base + priv->cur, buf, len);
len = R_MIN (len, b->rb_ref->size - b->rb_ref->cur);
st64 r = r_buf_read_at (b->rb_ref->parent, b->rb_ref->base + b->rb_ref->cur, buf, len);
if (r < 0) {
return r;
}
priv->cur += r;
b->rb_ref->cur += r;
return r;
}
static ut64 buf_ref_get_size(RBuffer *b) {
struct buf_ref_priv *priv = get_priv_ref (b);
return priv->size;
r_warn_if_fail (b->rb_ref);
return b->rb_ref->size;
}
static st64 buf_ref_seek(RBuffer *b, st64 addr, int whence) {
struct buf_ref_priv *priv = get_priv_ref (b);
r_warn_if_fail (b->rb_ref);
switch (whence) {
case R_BUF_CUR:
priv->cur += addr;
b->rb_ref->cur += addr;
break;
case R_BUF_SET:
priv->cur = addr;
b->rb_ref->cur = addr;
break;
case R_BUF_END:
priv->cur = priv->size + addr;
b->rb_ref->cur = b->rb_ref->size + addr;
break;
default:
r_warn_if_reached ();
return -1;
}
return priv->cur;
return b->rb_ref->cur;
}
static const RBufferMethods buffer_ref_methods = {

View File

@ -2,66 +2,63 @@
#include <r_util.h>
struct buf_sparse_priv {
RList *sparse;
ut64 offset;
};
static void buffer_sparse_free(void *a) {
RBufferSparse *s = (RBufferSparse *)a;
free (s->data);
free (s);
static void buffer_sparse_item_free(void *a) {
RBufferSparseItem *si = a;
free (si->data);
free (si);
}
static bool sparse_limits(RList *l, ut64 *max) {
bool set = false;
RBufferSparse *s;
RBufferSparseItem *si;
RListIter *iter;
r_list_foreach (l, iter, s) {
r_list_foreach (l, iter, si) {
if (set) {
if (max && s->to > *max) {
*max = s->to;
}
} else {
set = true;
if (max) {
*max = s->to;
if (max && si->to > *max) {
*max = si->to;
}
continue;
}
set = true;
if (max) {
*max = si->to;
}
}
return set;
}
static RBufferSparse *sparse_append(RList *l, ut64 addr, const ut8 *data, ut64 len) {
if (l && data) {
RBufferSparse *s = R_NEW0 (RBufferSparse);
if (s) {
s->data = calloc (1, len);
if (s->data) {
s->from = addr;
s->to = addr + len;
s->size = len;
memcpy (s->data, data, len);
return r_list_append (l, s)? s: NULL;
}
free (s);
}
static RBufferSparseItem *sparse_item_append(RList *l, ut64 addr, const ut8 *data, ut64 len) {
if (!(l && data)) {
return NULL;
}
return NULL;
RBufferSparseItem *si = R_NEW0 (RBufferSparseItem);
if (!si) {
return NULL;
}
si->data = calloc (sizeof (ut8), len);
if (!si->data) {
free (si);
return NULL;
}
si->from = addr;
si->to = addr + len;
si->size = len;
memcpy (si->data, data, len);
return r_list_append (l, si)? si: NULL;
}
//ret -1 if failed; # of bytes copied if success
static st64 sparse_write(RList *l, ut64 addr, const ut8 *data, ut64 len) {
RBufferSparse *s;
RBufferSparseItem *si;
RListIter *iter;
ut64 olen = len;
r_list_foreach (l, iter, s) {
if (addr >= s->from && addr < s->to) {
ut64 delta = addr - s->from;
ut64 reallen = s->size - delta >= len? len: s->size - delta;
memcpy (s->data + delta, data, reallen);
r_list_foreach (l, iter, si) {
if (addr >= si->from && addr < si->to) {
ut64 delta = addr - si->from;
ut64 reallen = si->size - delta >= len? len: si->size - delta;
memcpy (si->data + delta, data, reallen);
data += reallen;
len -= reallen;
addr += reallen;
@ -70,143 +67,136 @@ static st64 sparse_write(RList *l, ut64 addr, const ut8 *data, ut64 len) {
return olen;
}
}
if (len > 0 && !sparse_append (l, addr, data, len)) {
if (len > 0 && !sparse_item_append (l, addr, data, len)) {
return -1;
}
return olen;
}
static inline struct buf_sparse_priv *get_priv_sparse(RBuffer *b) {
struct buf_sparse_priv *priv = (struct buf_sparse_priv *)b->priv;
r_warn_if_fail (priv);
return priv;
}
static bool buf_sparse_init(RBuffer *b, const void *user) {
struct buf_sparse_priv *priv = R_NEW0 (struct buf_sparse_priv);
if (!priv) {
b->rb_sparse = R_NEW (RBufferSparse);
if (!b->rb_sparse) {
return false;
}
priv->sparse = r_list_newf (buffer_sparse_free);
priv->offset = 0;
b->priv = priv;
b->rb_sparse[0] = (RBufferSparse){.sparse = r_list_newf (buffer_sparse_item_free)};
return true;
}
static bool buf_sparse_fini(RBuffer *b) {
struct buf_sparse_priv *priv = get_priv_sparse (b);
r_list_free (priv->sparse);
R_FREE (b->priv);
r_warn_if_fail (b->rb_sparse);
r_list_free (b->rb_sparse->sparse);
R_FREE (b->rb_sparse);
return true;
}
static bool buf_sparse_resize(RBuffer *b, ut64 newsize) {
struct buf_sparse_priv *priv = get_priv_sparse (b);
r_warn_if_fail (b->rb_sparse);
RListIter *iter, *tmp;
RBufferSparse *s;
RBufferSparseItem *si;
r_list_foreach_safe (priv->sparse, iter, tmp, s) {
if (s->from >= newsize) {
r_list_delete (priv->sparse, iter);
} else if (s->to >= newsize) {
RBufferSparse *ns = R_NEW (RBufferSparse);
ns->from = s->from;
ns->to = newsize;
ns->size = ns->to - ns->from;
ut8 *tmp = realloc (s->data, s->size);
r_list_foreach_safe (b->rb_sparse->sparse, iter, tmp, si) {
if (si->from >= newsize) {
r_list_delete (b->rb_sparse->sparse, iter);
} else if (si->to >= newsize) {
RBufferSparseItem *nsi = R_NEW (RBufferSparseItem);
nsi->from = si->from;
nsi->to = newsize;
nsi->size = nsi->to - nsi->from;
ut8 *tmp = realloc (si->data, si->size);
if (!tmp) {
free (ns);
free (nsi);
return false;
}
// otherwise it will be double-freed by r_list_delete
s->data = NULL;
ns->data = tmp;
ns->written = s->written;
r_list_append (priv->sparse, ns);
r_list_delete (priv->sparse, iter);
si->data = NULL;
nsi->data = tmp;
nsi->written = si->written;
r_list_append (b->rb_sparse->sparse, nsi);
r_list_delete (b->rb_sparse->sparse, iter);
}
}
ut64 max;
max = sparse_limits (priv->sparse, &max)? max: 0;
max = sparse_limits (b->rb_sparse->sparse, &max)? max: 0;
if (max < newsize) {
return !!sparse_write (priv->sparse, newsize - 1, &b->Oxff_priv, 1);
return !!sparse_write (b->rb_sparse->sparse, newsize - 1, &b->Oxff_priv, 1);
}
return true;
}
static ut64 buf_sparse_size(RBuffer *b) {
struct buf_sparse_priv *priv = get_priv_sparse (b);
r_warn_if_fail (b->rb_sparse);
ut64 max;
return sparse_limits (priv->sparse, &max)? max: 0;
return sparse_limits (b->rb_sparse->sparse, &max)? max: 0;
}
static st64 buf_sparse_read(RBuffer *b, ut8 *buf, ut64 len) {
struct buf_sparse_priv *priv = get_priv_sparse (b);
RBufferSparse *c;
r_warn_if_fail (b->rb_sparse);
RBufferSparseItem *si;
RListIter *iter;
ut64 max = 0;
memset (buf, b->Oxff_priv, len);
r_list_foreach (priv->sparse, iter, c) {
if (max < c->to) {
max = c->to;
r_list_foreach (b->rb_sparse->sparse, iter, si) {
if (max < si->to) {
max = si->to;
}
if (priv->offset < c->to && c->from < priv->offset + len) {
if (priv->offset < c->from) {
ut64 l = R_MIN (priv->offset + len - c->from, c->size);
memcpy (buf + c->from - priv->offset, c->data, l);
} else {
ut64 l = R_MIN (c->to - priv->offset, len);
memcpy (buf, c->data + priv->offset - c->from, l);
}
if (!(b->rb_sparse->offset < si->to && si->from < b->rb_sparse->offset + len)) {
continue;
}
if (b->rb_sparse->offset < si->from) {
const ut64 l = R_MIN (b->rb_sparse->offset + len - si->from, si->size);
memcpy (buf + si->from - b->rb_sparse->offset, si->data, l);
} else {
const ut64 l = R_MIN (si->to - b->rb_sparse->offset, len);
memcpy (buf, si->data + b->rb_sparse->offset - si->from, l);
}
}
if (priv->offset > max) {
if (b->rb_sparse->offset > max) {
return -1;
}
ut64 r = R_MIN (max - priv->offset, len);
priv->offset += r;
ut64 r = R_MIN (max - b->rb_sparse->offset, len);
b->rb_sparse->offset += r;
return r;
}
static st64 buf_sparse_write(RBuffer *b, const ut8 *buf, ut64 len) {
struct buf_sparse_priv *priv = get_priv_sparse (b);
st64 r = sparse_write (priv->sparse, priv->offset, buf, len);
priv->offset += r;
r_warn_if_fail (b->rb_sparse);
st64 r = sparse_write (b->rb_sparse->sparse, b->rb_sparse->offset, buf, len);
b->rb_sparse->offset += r;
return r;
}
static st64 buf_sparse_seek(RBuffer *b, st64 addr, int whence) {
struct buf_sparse_priv *priv = get_priv_sparse (b);
r_warn_if_fail (b->rb_sparse);
ut64 max;
if (addr < 0 && (-addr) > (st64)priv->offset) {
if (addr < 0 && (-addr) > (st64)b->rb_sparse->offset) {
return -1;
}
switch (whence) {
case R_BUF_CUR:
priv->offset += addr;
b->rb_sparse->offset += addr;
break;
case R_BUF_SET:
priv->offset = addr;
b->rb_sparse->offset = addr;
break;
case R_BUF_END:
if (!sparse_limits (priv->sparse, &max)) {
if (!sparse_limits (b->rb_sparse->sparse, &max)) {
max = 0;
}
priv->offset = max + addr;
b->rb_sparse->offset = max + addr;
break;
default:
r_warn_if_reached ();
return -1;
}
return priv->offset;
return b->rb_sparse->offset;
}
static RList *buf_sparse_nonempty_list(RBuffer *b) {
struct buf_sparse_priv *priv = get_priv_sparse (b);
return r_list_clone (priv->sparse, NULL);
r_warn_if_fail (b->rb_sparse);
return r_list_clone (b->rb_sparse->sparse, NULL);
}
static const RBufferMethods buffer_sparse_methods = {