Rizin
unix-like reverse engineering framework and cli tools
text.c
Go to the documentation of this file.
1 // SPDX-FileCopyrightText: 2020 thestr4ng3r <info@florianmaerkl.de>
2 // SPDX-License-Identifier: MIT
3 
4 #include "sdb.h"
5 
6 #include <fcntl.h>
7 #include <limits.h>
8 #include <sys/stat.h>
9 #if HAVE_HEADER_SYS_MMAN_H
10 #include <sys/mman.h>
11 #endif
12 #include "sdb_private.h"
13 
64 static int cmp_ns(const void *a, const void *b) {
65  const SdbNs *nsa = a;
66  const SdbNs *cia = b;
67  return strcmp(nsa->name, cia->name);
68 }
69 
70 // n = position we are currently looking at
71 // p = position until we have already written everything
72 // flush a block of text that doesn't have to be escaped
73 #define FLUSH \
74  do { \
75  if (p != n) { \
76  write_(fd, p, n - p); \
77  p = n; \
78  } \
79  } while (0)
80 // write and escape a string from str to fd
81 #define ESCAPE_LOOP(fd, str, escapes) \
82  do { \
83  const char *p = str; \
84  const char *n = p; \
85  while (*n) { \
86  switch (*n) { escapes } \
87  n++; \
88  } \
89  FLUSH; \
90  } while (0)
91 #define ESCAPE(c, repl, replsz) \
92  case c: \
93  FLUSH; \
94  p++; \
95  write_(fd, "\\" repl, replsz + 1); \
96  break;
97 
98 static void write_path(int fd, SdbList *path) {
99  write_(fd, "/", 1); // always print a /, even if path is empty
100  SdbListIter *it;
101  const char *path_token;
102  bool first = true;
103  ls_foreach (path, it, path_token) {
104  if (first) {
105  first = false;
106  } else {
107  write_(fd, "/", 1);
108  }
109  ESCAPE_LOOP(fd, path_token,
110  ESCAPE('\\', "\\", 1);
111  ESCAPE('/', "/", 1);
112  ESCAPE('\n', "n", 1);
113  ESCAPE('\r', "r", 1););
114  }
115 }
116 
117 static void write_key(int fd, const char *k) {
118  // escape leading '/'
119  if (*k == '/') {
120  write_(fd, "\\", 1);
121  }
122  ESCAPE_LOOP(fd, k,
123  ESCAPE('\\', "\\", 1);
124  ESCAPE('=', "=", 1);
125  ESCAPE('\n', "n", 1);
126  ESCAPE('\r', "r", 1););
127 }
128 
129 static void write_value(int fd, const char *v) {
130  ESCAPE_LOOP(fd, v,
131  ESCAPE('\\', "\\", 1);
132  ESCAPE('\n', "n", 1);
133  ESCAPE('\r', "r", 1););
134 }
135 #undef FLUSH
136 #undef ESCAPE_LOOP
137 #undef ESCAPE
138 
139 static bool save_kv_cb(void *user, const char *k, const char *v) {
140  int fd = *(int *)user;
141  write_key(fd, k);
142  write_(fd, "=", 1);
143  write_value(fd, v);
144  write_(fd, "\n", 1);
145  return true;
146 }
147 
148 static bool text_save(Sdb *s, int fd, bool sort, SdbList *path) {
149  // path
150  write_path(fd, path);
151  write_(fd, "\n", 1);
152 
153  // k=v entries
154  if (sort) {
155  SdbList *l = sdb_foreach_list(s, true);
156  SdbKv *kv;
157  SdbListIter *it;
158  ls_foreach (l, it, kv) {
159  save_kv_cb(&fd, sdbkv_key(kv), sdbkv_value(kv));
160  }
161  ls_free(l);
162  } else {
163  // This is faster when sorting is not needed.
165  }
166 
167  // sub-namespaces
168  SdbList *l = s->ns;
169  if (sort) {
170  l = ls_clone(l);
171  ls_sort(l, cmp_ns);
172  }
173  SdbNs *ns;
174  SdbListIter *it;
175  ls_foreach (l, it, ns) {
176  write_(fd, "\n", 1);
177  ls_push(path, ns->name);
178  text_save(ns->sdb, fd, sort, path);
179  ls_pop(path);
180  }
181  if (l != s->ns) {
182  ls_free(l);
183  }
184 
185  return true;
186 }
187 #undef write_
188 
189 RZ_API bool sdb_text_save_fd(Sdb *s, int fd, bool sort) {
190  SdbList *path = ls_new();
191  if (!path) {
192  return false;
193  }
194  bool r = text_save(s, fd, sort, path);
195  ls_free(path);
196  return r;
197 }
198 
199 RZ_API bool sdb_text_save(Sdb *s, const char *file, bool sort) {
200  int fd = open(file, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY, 0644);
201  if (fd < 0) {
202  return false;
203  }
204  bool r = sdb_text_save_fd(s, fd, sort);
205  close(fd);
206  return r;
207 }
208 
209 typedef enum {
215 
216 typedef struct {
217  bool eof;
218  char *buf;
219  size_t bufsz;
221  Sdb *cur_db; // current namespace, changes when encountering a path line
222  size_t pos; // current processing position in the buffer
223  size_t line_begin;
224  size_t token_begin; // beginning of the currently processed token in the buffer
225  size_t shift; // amount to shift chars to the left (from unescaping)
226  SdbList /*<size_t>*/ *path;
228  bool unescape; // whether the prev char was a backslash, i.e. the current one is escaped
229 } LoadCtx;
230 
231 // to be called at the end of a line.
232 // save all the data processed from the line into the database.
233 // assumes that the ctx->buf is allocated until ctx->buf[ctx->pos] inclusive!
235  ctx->unescape = false;
236  // finish up the line
237  ctx->buf[ctx->pos - ctx->shift] = '\0';
238  switch (ctx->state) {
239  case STATE_PATH: {
240  ls_push(ctx->path, (void *)ctx->token_begin);
241  SdbListIter *it;
242  void *token_off_tmp;
243  ctx->cur_db = ctx->root_db;
244  ls_foreach (ctx->path, it, token_off_tmp) {
245  size_t token_off = (size_t)token_off_tmp;
246  if (!ctx->buf[token_off]) {
247  continue;
248  }
249  ctx->cur_db = sdb_ns(ctx->cur_db, ctx->buf + token_off, 1);
250  if (!ctx->cur_db) {
251  ctx->cur_db = ctx->root_db;
252  break;
253  }
254  }
255  ls_destroy(ctx->path);
256  break;
257  }
258  case STATE_VALUE: {
259  const char *k = ctx->buf + ctx->line_begin;
260  const char *v = ctx->buf + ctx->token_begin;
261  if (!*k || !*v) {
262  break;
263  }
264  sdb_set(ctx->cur_db, k, v, 0);
265  break;
266  }
267  default:
268  break;
269  }
270  // prepare for next line
271  ctx->shift = 0;
272  ctx->state = STATE_NEWLINE;
273 }
274 
275 static inline char unescape_raw_char(char c) {
276  switch (c) {
277  case 'n':
278  return '\n';
279  case 'r':
280  return '\r';
281  case 't':
282  return '\t';
283  default:
284  return c;
285  }
286 }
287 
289  char c = ctx->buf[ctx->pos];
290  if (c == '\n' || c == '\r') {
292  ctx->pos++;
293  return;
294  }
295 
296  if (ctx->state == STATE_NEWLINE) {
297  ctx->line_begin = ctx->pos;
298  // at the start of a line, decide whether it's a path or a k=v
299  // by whether there is a leading slash.
300  if (c == '/') {
301  ctx->state = STATE_PATH;
302  ctx->token_begin = ctx->pos + 1;
303  ctx->pos++;
304  c = ctx->buf[ctx->pos];
305  return;
306  }
307  ctx->state = STATE_KEY;
308  }
309 
310  if (ctx->unescape) {
311  ctx->buf[ctx->pos - ctx->shift] = unescape_raw_char(c);
312  ctx->unescape = false;
313  } else if (c == '\\') {
314  // got a backslash, the next char, unescape in the next iteration or die!
315  ctx->shift++;
316  ctx->unescape = true;
317  } else if (ctx->state == STATE_PATH && c == '/') {
318  // new path token
319  ctx->buf[ctx->pos - ctx->shift] = '\0';
320  ls_push(ctx->path, (void *)ctx->token_begin);
321  ctx->token_begin = ctx->pos + 1;
322  ctx->shift = 0;
323  } else if (ctx->state == STATE_KEY && c == '=') {
324  // switch from key to value mode
325  ctx->buf[ctx->pos - ctx->shift] = '\0';
326  ctx->token_begin = ctx->pos + 1;
327  ctx->shift = 0;
328  ctx->state = STATE_VALUE;
329  } else if (ctx->shift) {
330  // just some char, shift it back if necessary
331  ctx->buf[ctx->pos - ctx->shift] = c;
332  }
333  ctx->pos++;
334 }
335 
337  // load_process_line needs ctx.buf[ctx.pos] to be allocated!
338  // so we need room for one additional byte after the buffer.
339  size_t linesz = ctx->bufsz - ctx->line_begin;
340  char *linebuf = malloc(linesz + 1);
341  if (!linebuf) {
342  return false;
343  }
344  memcpy(linebuf, ctx->buf + ctx->line_begin, linesz);
345  ctx->buf = linebuf;
346  // shift everything by the size we skipped
347  ctx->bufsz -= ctx->line_begin;
348  ctx->pos = linesz;
349  ctx->token_begin -= ctx->line_begin;
350  SdbListIter *it;
351  void *token_off_tmp;
352  ls_foreach (ctx->path, it, token_off_tmp) {
353  it->data = (void *)((size_t)token_off_tmp - ctx->line_begin);
354  }
355  ctx->line_begin = 0;
357  free(linebuf);
358  ctx->buf = NULL;
359  return true;
360 }
361 
362 static void load_ctx_fini(LoadCtx *ctx) {
363  ls_free(ctx->path);
364 }
365 
366 static bool load_ctx_init(LoadCtx *ctx, Sdb *s, char *buf, size_t sz) {
367  ctx->eof = false;
368  ctx->buf = buf;
369  ctx->bufsz = sz;
370  ctx->root_db = s;
371  ctx->cur_db = s;
372  ctx->pos = 0;
373  ctx->line_begin = 0;
374  ctx->token_begin = 0;
375  ctx->shift = 0;
376  ctx->path = ls_new();
377  ctx->state = STATE_NEWLINE;
378  ctx->unescape = false;
379  if (!ctx->buf || !ctx->path) {
381  return false;
382  }
383  return true;
384 }
385 
386 RZ_API bool sdb_text_load_buf(Sdb *s, char *buf, size_t sz) {
387  if (!sz) {
388  return true;
389  }
390  LoadCtx ctx;
391  if (!load_ctx_init(&ctx, s, buf, sz)) {
392  return false;
393  }
394  bool ret = true;
395  while (ctx.pos < ctx.bufsz) {
397  }
398  if (ctx.line_begin < ctx.bufsz && ctx.state != STATE_NEWLINE) {
400  }
401  load_ctx_fini(&ctx);
402  return ret;
403 }
404 
405 RZ_API bool sdb_text_load(Sdb *s, const char *file) {
406  int fd = open(file, O_RDONLY | O_BINARY);
407  if (fd < 0) {
408  return false;
409  }
410  bool r = false;
411  struct stat st;
412  if (fstat(fd, &st) || !st.st_size) {
413  goto beach;
414  }
415 #if HAVE_HEADER_SYS_MMAN_H
416  char *x = mmap(0, st.st_size, PROT_READ | PROT_WRITE, MAP_PRIVATE, fd, 0);
417  if (x == MAP_FAILED) {
418  goto beach;
419  }
420 #else
421  char *x = calloc(1, st.st_size);
422  if (!x) {
423  goto beach;
424  }
425  if (read(fd, x, st.st_size) != st.st_size) {
426  free(x);
427  goto beach;
428  }
429 #endif
430  r = sdb_text_load_buf(s, x, st.st_size);
431 #if HAVE_HEADER_SYS_MMAN_H
432  munmap(x, st.st_size);
433 #else
434  free(x);
435 #endif
436 beach:
437  close(fd);
438  return r;
439 }
#define O_BINARY
Definition: cpipe.c:13
#define RZ_API
#define NULL
Definition: cris-opc.c:27
#define r
Definition: crypto_rc6.c:12
static static fork const void static count static fd const char const char static newpath const char static path const char path
Definition: sflib.h:35
static static fork const void static count close
Definition: sflib.h:33
static static sync static getppid static getegid const char static filename char static len const char char static bufsiz static mask static vfork const void static prot static getpgrp const char static swapflags static arg static fd static protocol static who struct sockaddr static addrlen static backlog struct timeval struct timezone static tz const struct iovec static count static mode const void const struct sockaddr static tolen const char static pathname void static offset fstat
Definition: sflib.h:107
const char * k
Definition: dsignal.c:11
const char * v
Definition: dsignal.c:12
RZ_API void Ht_() free(HtName_(Ht) *ht)
Definition: ht_inc.c:130
voidpf void * buf
Definition: ioapi.h:138
memcpy(mem, inblock.get(), min(CONTAINING_RECORD(inblock.get(), MEMBLOCK, data) ->size, size))
void * malloc(size_t size)
Definition: malloc.c:123
void * calloc(size_t number, size_t size)
Definition: malloc.c:102
static static fork const void static count static fd const char const char static newpath char char char static envp time_t static t const char static mode static whence const char static dir time_t static t unsigned static seconds const char struct utimbuf static buf static inc static sig const char static mode static oldfd struct tms static buf static getgid static geteuid const char static filename static arg static mask struct ustat static ubuf static getppid static setsid static egid sigset_t static set struct timeval struct timezone static tz fd_set fd_set fd_set struct timeval static timeout const char char static bufsiz const char static swapflags mmap
Definition: sflib.h:115
static const void static count static fd struct stat static buf struct pollfd unsigned static timeout void static offset munmap
Definition: sflib.h:43
RZ_API SdbList * ls_new(void)
Definition: ls.c:16
RZ_API void ls_destroy(SdbList *list)
Definition: ls.c:176
RZ_API void * ls_pop(SdbList *list)
Definition: ls.c:244
RZ_API void ls_free(SdbList *list)
Definition: ls.c:191
RZ_API SdbList * ls_clone(SdbList *list)
Definition: ls.c:265
RZ_API bool ls_sort(SdbList *list, SdbListComparator cmp)
Definition: ls.c:119
#define ls_push(x, y)
Definition: ls.h:75
#define ls_foreach(list, it, pos)
Definition: ls.h:31
int x
Definition: mipsasm.c:20
RZ_API Sdb * sdb_ns(Sdb *s, const char *name, int create)
Definition: ns.c:186
static RzSocket * s
Definition: rtr.c:28
RZ_API int sdb_set(Sdb *s, const char *key, const char *val, ut32 cas)
Definition: sdb.c:611
RZ_API bool sdb_foreach(Sdb *s, SdbForeachCallback cb, void *user)
Definition: sdb.c:758
RZ_API SdbList * sdb_foreach_list(Sdb *s, bool sorted)
Definition: sdb.c:630
#define write_(fd, buf, count)
Definition: sdb_private.h:18
static char * sdbkv_key(const SdbKv *kv)
Definition: sdbht.h:21
static char * sdbkv_value(const SdbKv *kv)
Definition: sdbht.h:25
#define O_WRONLY
Definition: sftypes.h:487
#define PROT_READ
Definition: sftypes.h:95
#define O_CREAT
Definition: sftypes.h:489
#define PROT_WRITE
Definition: sftypes.h:96
#define MAP_PRIVATE
Definition: sftypes.h:102
int size_t
Definition: sftypes.h:40
#define O_RDONLY
Definition: sftypes.h:486
#define O_TRUNC
Definition: sftypes.h:492
#define b(i)
Definition: sha256.c:42
#define c(i)
Definition: sha256.c:43
#define a(i)
Definition: sha256.c:41
Definition: text.c:216
SdbList * path
Definition: text.c:226
size_t token_begin
Definition: text.c:224
bool unescape
Definition: text.c:228
Sdb * root_db
Definition: text.c:220
Sdb * cur_db
Definition: text.c:221
size_t shift
Definition: text.c:225
size_t line_begin
Definition: text.c:223
bool eof
Definition: text.c:217
LoadState state
Definition: text.c:227
char * buf
Definition: text.c:218
size_t pos
Definition: text.c:222
size_t bufsz
Definition: text.c:219
Definition: gzappend.c:170
Definition: ls.h:17
void * data
Definition: ls.h:18
Definition: ls.h:22
Definition: sdbht.h:14
Definition: sdb.h:88
char * name
Definition: sdb.h:89
Sdb * sdb
Definition: sdb.h:91
Definition: sdb.h:63
Definition: sftypes.h:80
static int cmp_ns(const void *a, const void *b)
Definition: text.c:64
static bool load_ctx_init(LoadCtx *ctx, Sdb *s, char *buf, size_t sz)
Definition: text.c:366
static void write_path(int fd, SdbList *path)
Definition: text.c:98
static void write_key(int fd, const char *k)
Definition: text.c:117
RZ_API bool sdb_text_save(Sdb *s, const char *file, bool sort)
Definition: text.c:199
#define ESCAPE(c, repl, replsz)
Definition: text.c:91
RZ_API bool sdb_text_load(Sdb *s, const char *file)
Definition: text.c:405
RZ_API bool sdb_text_load_buf(Sdb *s, char *buf, size_t sz)
Definition: text.c:386
static void load_process_single_char(LoadCtx *ctx)
Definition: text.c:288
static bool text_save(Sdb *s, int fd, bool sort, SdbList *path)
Definition: text.c:148
static void load_ctx_fini(LoadCtx *ctx)
Definition: text.c:362
static bool save_kv_cb(void *user, const char *k, const char *v)
Definition: text.c:139
static void write_value(int fd, const char *v)
Definition: text.c:129
#define ESCAPE_LOOP(fd, str, escapes)
Definition: text.c:81
RZ_API bool sdb_text_save_fd(Sdb *s, int fd, bool sort)
Definition: text.c:189
static void load_process_line(LoadCtx *ctx)
Definition: text.c:234
static char unescape_raw_char(char c)
Definition: text.c:275
LoadState
Definition: text.c:209
@ STATE_KEY
Definition: text.c:212
@ STATE_NEWLINE
Definition: text.c:210
@ STATE_PATH
Definition: text.c:211
@ STATE_VALUE
Definition: text.c:213
static bool load_process_final_line(LoadCtx *ctx)
Definition: text.c:336
static const z80_opcode fd[]
Definition: z80_tab.h:997
int read(izstream &zs, T *x, Items items)
Definition: zstream.h:115