Files
damus/nostrdb/src/block.c
William Casarin 919f644cba add assert to catch potential bug
Signed-off-by: William Casarin <jb55@jb55.com>
2025-08-11 16:40:01 -07:00

206 lines
4.3 KiB
C

#include "nostrdb.h"
#include "block.h"
#include <stdlib.h>
int push_str_block(struct cursor *buf, const char *content, struct ndb_str_block *block) {
return cursor_push_varint(buf, block->str - content) &&
cursor_push_varint(buf, block->len);
}
int pull_str_block(struct cursor *buf, const char *content, struct ndb_str_block *block) {
uint32_t start;
if (!cursor_pull_varint_u32(buf, &start))
return 0;
block->str = content + start;
return cursor_pull_varint_u32(buf, &block->len);
}
static int pull_nostr_bech32_type(struct cursor *cur, enum nostr_bech32_type *type)
{
uint64_t inttype;
if (!cursor_pull_varint(cur, &inttype))
return 0;
if (inttype <= 0 || inttype > NOSTR_BECH32_KNOWN_TYPES)
return 0;
*type = inttype;
return 1;
}
static int pull_bech32_mention(const char *content, struct cursor *cur, struct ndb_mention_bech32_block *block) {
uint16_t size;
unsigned char *start;
struct cursor bech32;
if (!pull_str_block(cur, content, &block->str))
return 0;
if (!cursor_pull_u16(cur, &size))
return 0;
if (!pull_nostr_bech32_type(cur, &block->bech32.type))
return 0;
make_cursor(cur->p, cur->p + size, &bech32);
start = cur->p;
if (!parse_nostr_bech32_buffer(&bech32, block->bech32.type, &block->bech32))
return 0;
//assert(bech32.p == start + size);
cur->p = start + size;
return 1;
}
static int pull_invoice(const char *content, struct cursor *cur,
struct ndb_invoice_block *block)
{
if (!pull_str_block(cur, content, &block->invstr))
return 0;
return ndb_decode_invoice(cur, &block->invoice);
}
static int pull_block_type(struct cursor *cur, enum ndb_block_type *type)
{
uint32_t itype;
*type = 0;
if (!cursor_pull_varint_u32(cur, &itype))
return 0;
if (itype <= 0 || itype > NDB_NUM_BLOCK_TYPES)
return 0;
*type = itype;
return 1;
}
static int pull_block(const char *content, struct cursor *cur, struct ndb_block *block)
{
unsigned char *start = cur->p;
if (!pull_block_type(cur, &block->type))
return 0;
switch (block->type) {
case BLOCK_HASHTAG:
case BLOCK_TEXT:
case BLOCK_URL:
if (!pull_str_block(cur, content, &block->block.str))
goto fail;
break;
case BLOCK_MENTION_INDEX:
if (!cursor_pull_varint_u32(cur, &block->block.mention_index))
goto fail;
break;
case BLOCK_MENTION_BECH32:
if (!pull_bech32_mention(content, cur, &block->block.mention_bech32))
goto fail;
break;
case BLOCK_INVOICE:
// we only push invoice strs here
if (!pull_invoice(content, cur, &block->block.invoice))
goto fail;
break;
}
return 1;
fail:
cur->p = start;
return 0;
}
enum ndb_block_type ndb_get_block_type(struct ndb_block *block) {
return block->type;
}
// BLOCK ITERATORS
void ndb_blocks_iterate_start(const char *content, struct ndb_blocks *blocks, struct ndb_block_iterator *iter) {
iter->blocks = blocks;
iter->content = content;
iter->p = blocks->blocks;
}
struct ndb_block *ndb_blocks_iterate_next(struct ndb_block_iterator *iter)
{
struct cursor cur;
cur.start = iter->blocks->blocks;
cur.p = iter->p;
cur.end = iter->blocks->blocks + iter->blocks->blocks_size;
while (cur.p < cur.end) {
if (!pull_block(iter->content, &cur, &iter->block)) {
iter->p = cur.p;
return NULL;
} else {
iter->p = cur.p;
return &iter->block;
}
}
return NULL;
}
// STR BLOCKS
struct ndb_str_block *ndb_block_str(struct ndb_block *block)
{
switch (block->type) {
case BLOCK_HASHTAG:
case BLOCK_TEXT:
case BLOCK_URL:
return &block->block.str;
case BLOCK_MENTION_INDEX:
return NULL;
case BLOCK_MENTION_BECH32:
return &block->block.mention_bech32.str;
case BLOCK_INVOICE:
return &block->block.invoice.invstr;
}
return NULL;
}
const char *ndb_str_block_ptr(struct ndb_str_block *str_block) {
return str_block->str;
}
uint32_t ndb_str_block_len(struct ndb_str_block *str_block) {
return str_block->len;
}
struct nostr_bech32 *ndb_bech32_block(struct ndb_block *block) {
return &block->block.mention_bech32.bech32;
}
// total size including padding
size_t ndb_blocks_total_size(struct ndb_blocks *blocks) {
assert(blocks->total_size < 1000000);
return blocks->total_size;
}
void ndb_blocks_free(struct ndb_blocks *blocks) {
if ((blocks->flags & NDB_BLOCK_FLAG_OWNED) != NDB_BLOCK_FLAG_OWNED)
return;
free(blocks);
}
int ndb_blocks_flags(struct ndb_blocks *blocks) {
return blocks->flags;
}
int ndb_blocks_word_count(struct ndb_blocks *blocks) {
return blocks->words;
}