Prep 1.27
[dwarves.git] / gobuffer.c
blobc439c48bb775593fe1c33626036b104b0ee113c0
1 /*
2 SPDX-License-Identifier: GPL-2.0-only
4 Copyright (C) 2008 Arnaldo Carvalho de Melo <acme@redhat.com>
6 Grow only buffer, add entries but never delete
7 */
9 #include "gobuffer.h"
11 #include <search.h>
12 #include <stdint.h>
13 #include <stdlib.h>
14 #include <stdio.h>
15 #include <string.h>
16 #include <zlib.h>
17 #include <errno.h>
19 #include "dutil.h"
21 #define GOBUFFER__BCHUNK (8 * 1024)
22 #define GOBUFFER__ZCHUNK (8 * 1024)
24 void gobuffer__init(struct gobuffer *gb)
26 gb->entries = NULL;
27 gb->nr_entries = gb->allocated_size = 0;
28 /* 0 == NULL */
29 gb->index = 1;
32 struct gobuffer *gobuffer__new(void)
34 struct gobuffer *gb = malloc(sizeof(*gb));
36 if (gb != NULL)
37 gobuffer__init(gb);
39 return gb;
42 void __gobuffer__delete(struct gobuffer *gb)
44 if (gb == NULL)
45 return;
47 zfree(&gb->entries);
50 void gobuffer__delete(struct gobuffer *gb)
52 __gobuffer__delete(gb);
53 free(gb);
56 void *gobuffer__ptr(const struct gobuffer *gb, unsigned int s)
58 return s ? gb->entries + s : NULL;
61 int gobuffer__allocate(struct gobuffer *gb, unsigned int len)
63 const unsigned int rc = gb->index;
64 const unsigned int index = gb->index + len;
66 if (index >= gb->allocated_size) {
67 unsigned int allocated_size = (gb->allocated_size +
68 GOBUFFER__BCHUNK);
69 if (allocated_size < index)
70 allocated_size = index + GOBUFFER__BCHUNK;
71 char *entries = realloc(gb->entries, allocated_size);
73 if (entries == NULL)
74 return -ENOMEM;
76 gb->allocated_size = allocated_size;
77 gb->entries = entries;
80 gb->index = index;
81 return rc;
84 int gobuffer__add(struct gobuffer *gb, const void *s, unsigned int len)
86 const int rc = gobuffer__allocate(gb, len);
88 if (rc >= 0) {
89 ++gb->nr_entries;
90 memcpy(gb->entries + rc, s, len);
92 return rc;
95 void gobuffer__copy(const struct gobuffer *gb, void *dest)
97 if (gb->entries) {
98 memcpy(dest, gb->entries, gobuffer__size(gb));
99 } else {
100 /* gobuffer__size will be 0 or 1. */
101 memcpy(dest, "", gobuffer__size(gb));
105 void gobuffer__sort(struct gobuffer *gb, unsigned int size, int (*compar)(const void *, const void *))
107 qsort(gb->entries, gb->nr_entries, size, compar);
110 const void *gobuffer__compress(struct gobuffer *gb, unsigned int *size)
112 z_stream z = {
113 .zalloc = Z_NULL,
114 .zfree = Z_NULL,
115 .opaque = Z_NULL,
116 .avail_in = gobuffer__size(gb),
117 .next_in = (Bytef *)(gobuffer__entries(gb) ? : ""),
119 void *bf = NULL;
120 unsigned int bf_size = 0;
122 if (deflateInit(&z, Z_BEST_COMPRESSION) != Z_OK)
123 goto out_free;
125 do {
126 const unsigned int new_bf_size = bf_size + GOBUFFER__ZCHUNK;
127 void *nbf = realloc(bf, new_bf_size);
129 if (nbf == NULL)
130 goto out_close_and_free;
132 bf = nbf;
133 z.avail_out = GOBUFFER__ZCHUNK;
134 z.next_out = (Bytef *)bf + bf_size;
135 bf_size = new_bf_size;
136 if (deflate(&z, Z_FINISH) == Z_STREAM_ERROR)
137 goto out_close_and_free;
138 } while (z.avail_out == 0);
140 deflateEnd(&z);
141 *size = bf_size - z.avail_out;
142 out:
143 return bf;
145 out_close_and_free:
146 deflateEnd(&z);
147 out_free:
148 free(bf);
149 bf = NULL;
150 goto out;