summaryrefslogtreecommitdiff
path: root/upb/sink.c
blob: 6ef571838eeafd47a3105afeb550dfd6d76d7e07 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87

#include "upb/sink.h"

bool upb_bufsrc_putbuf(const char *buf, size_t len, upb_bytessink sink) {
  void *subc;
  bool ret;
  upb_bufhandle handle = UPB_BUFHANDLE_INIT;
  handle.buf = buf;
  ret = upb_bytessink_start(&sink, len, &subc);
  if (ret && len != 0) {
    ret = (upb_bytessink_putbuf(&sink, subc, buf, len, &handle) >= len);
  }
  if (ret) {
    ret = upb_bytessink_end(&sink);
  }
  return ret;
}

struct upb_bufsink {
  upb_byteshandler handler;
  upb_bytessink sink;
  upb_env *env;
  char *ptr;
  size_t len, size;
};

static void *upb_bufsink_start(void *_sink, const void *hd, size_t size_hint) {
  upb_bufsink *sink = _sink;
  UPB_UNUSED(hd);
  UPB_UNUSED(size_hint);
  sink->len = 0;
  return sink;
}

static size_t upb_bufsink_string(void *_sink, const void *hd, const char *ptr,
                                size_t len, const upb_bufhandle *handle) {
  upb_bufsink *sink = _sink;
  size_t new_size = sink->size;

  UPB_ASSERT(new_size > 0);
  UPB_UNUSED(hd);
  UPB_UNUSED(handle);

  while (sink->len + len > new_size) {
    new_size *= 2;
  }

  if (new_size != sink->size) {
    sink->ptr = upb_env_realloc(sink->env, sink->ptr, sink->size, new_size);
    sink->size = new_size;
  }

  memcpy(sink->ptr + sink->len, ptr, len);
  sink->len += len;

  return len;
}

upb_bufsink *upb_bufsink_new(upb_env *env) {
  upb_bufsink *sink = upb_env_malloc(env, sizeof(upb_bufsink));
  upb_byteshandler_init(&sink->handler);
  upb_byteshandler_setstartstr(&sink->handler, upb_bufsink_start, NULL);
  upb_byteshandler_setstring(&sink->handler, upb_bufsink_string, NULL);

  upb_bytessink_reset(&sink->sink, &sink->handler, sink);

  sink->env = env;
  sink->size = 32;
  sink->ptr = upb_env_malloc(env, sink->size);
  sink->len = 0;

  return sink;
}

void upb_bufsink_free(upb_bufsink *sink) {
  upb_env_free(sink->env, sink->ptr);
  upb_env_free(sink->env, sink);
}

upb_bytessink *upb_bufsink_sink(upb_bufsink *sink) {
  return &sink->sink;
}

const char *upb_bufsink_getdata(const upb_bufsink *sink, size_t *len) {
  *len = sink->len;
  return sink->ptr;
}
generated by cgit on debian on lair
contact matthew@masot.net with questions or feedback