xref: /vim-8.2.3635/src/blob.c (revision 94688b8a)
1 /* vi:set ts=8 sts=4 sw=4 noet:
2  *
3  * VIM - Vi IMproved	by Bram Moolenaar
4  *
5  * Do ":help uganda"  in Vim to read copying and usage conditions.
6  * Do ":help credits" in Vim to see a list of people who contributed.
7  * See README.txt for an overview of the Vim source code.
8  */
9 
10 /*
11  * blob.c: Blob support by Yasuhiro Matsumoto
12  */
13 
14 #include "vim.h"
15 
16 #if defined(FEAT_EVAL) || defined(PROTO)
17 
18 /*
19  * Allocate an empty blob.
20  * Caller should take care of the reference count.
21  */
22     blob_T *
23 blob_alloc(void)
24 {
25     blob_T *blob = (blob_T *)alloc_clear(sizeof(blob_T));
26 
27     if (blob != NULL)
28 	ga_init2(&blob->bv_ga, 1, 100);
29     return blob;
30 }
31 
32 /*
33  * Allocate an empty blob for a return value, with reference count set.
34  * Returns OK or FAIL.
35  */
36     int
37 rettv_blob_alloc(typval_T *rettv)
38 {
39     blob_T	*b = blob_alloc();
40 
41     if (b == NULL)
42 	return FAIL;
43 
44     rettv_blob_set(rettv, b);
45     return OK;
46 }
47 
48 /*
49  * Set a blob as the return value.
50  */
51     void
52 rettv_blob_set(typval_T *rettv, blob_T *b)
53 {
54     rettv->v_type = VAR_BLOB;
55     rettv->vval.v_blob = b;
56     if (b != NULL)
57 	++b->bv_refcount;
58 }
59 
60     int
61 blob_copy(typval_T *from, typval_T *to)
62 {
63     int	    ret = OK;
64 
65     to->v_type = VAR_BLOB;
66     if (from->vval.v_blob == NULL)
67 	to->vval.v_blob = NULL;
68     else if (rettv_blob_alloc(to) == FAIL)
69 	ret = FAIL;
70     else
71     {
72 	int  len = from->vval.v_blob->bv_ga.ga_len;
73 
74 	if (len > 0)
75 	{
76 	    to->vval.v_blob->bv_ga.ga_data =
77 			    vim_memsave(from->vval.v_blob->bv_ga.ga_data, len);
78 	    if (to->vval.v_blob->bv_ga.ga_data == NULL)
79 		len = 0;
80 	}
81 	to->vval.v_blob->bv_ga.ga_len = len;
82     }
83     return ret;
84 }
85 
86     void
87 blob_free(blob_T *b)
88 {
89     ga_clear(&b->bv_ga);
90     vim_free(b);
91 }
92 
93 /*
94  * Unreference a blob: decrement the reference count and free it when it
95  * becomes zero.
96  */
97     void
98 blob_unref(blob_T *b)
99 {
100     if (b != NULL && --b->bv_refcount <= 0)
101 	blob_free(b);
102 }
103 
104 /*
105  * Get the length of data.
106  */
107     long
108 blob_len(blob_T *b)
109 {
110     if (b == NULL)
111 	return 0L;
112     return b->bv_ga.ga_len;
113 }
114 
115 /*
116  * Get byte "idx" in blob "b".
117  * Caller must check that "idx" is valid.
118  */
119     int
120 blob_get(blob_T *b, int idx)
121 {
122     return ((char_u*)b->bv_ga.ga_data)[idx];
123 }
124 
125 /*
126  * Store one byte "c" in blob "b" at "idx".
127  * Caller must make sure that "idx" is valid.
128  */
129     void
130 blob_set(blob_T *b, int idx, char_u c)
131 {
132     ((char_u*)b->bv_ga.ga_data)[idx] = c;
133 }
134 
135 /*
136  * Return TRUE when two blobs have exactly the same values.
137  */
138     int
139 blob_equal(
140     blob_T	*b1,
141     blob_T	*b2)
142 {
143     int	    i;
144     int	    len1 = blob_len(b1);
145     int	    len2 = blob_len(b2);
146 
147     // empty and NULL are considered the same
148     if (len1 == 0 && len2 == 0)
149 	return TRUE;
150     if (b1 == b2)
151 	return TRUE;
152     if (len1 != len2)
153 	return FALSE;
154 
155     for (i = 0; i < b1->bv_ga.ga_len; i++)
156 	if (blob_get(b1, i) != blob_get(b2, i)) return FALSE;
157     return TRUE;
158 }
159 
160 /*
161  * Read "blob" from file "fd".
162  * Return OK or FAIL.
163  */
164     int
165 read_blob(FILE *fd, blob_T *blob)
166 {
167     struct stat	st;
168 
169     if (fstat(fileno(fd), &st) < 0)
170 	return FAIL;
171     if (ga_grow(&blob->bv_ga, st.st_size) == FAIL)
172 	return FAIL;
173     blob->bv_ga.ga_len = st.st_size;
174     if (fread(blob->bv_ga.ga_data, 1, blob->bv_ga.ga_len, fd)
175 						  < (size_t)blob->bv_ga.ga_len)
176 	return FAIL;
177     return OK;
178 }
179 
180 /*
181  * Write "blob" to file "fd".
182  * Return OK or FAIL.
183  */
184     int
185 write_blob(FILE *fd, blob_T *blob)
186 {
187     if (fwrite(blob->bv_ga.ga_data, 1, blob->bv_ga.ga_len, fd)
188 						  < (size_t)blob->bv_ga.ga_len)
189     {
190 	emsg(_(e_write));
191 	return FAIL;
192     }
193     return OK;
194 }
195 
196 /*
197  * Convert a blob to a readable form: "0z00112233.44556677.8899"
198  */
199     char_u *
200 blob2string(blob_T *blob, char_u **tofree, char_u *numbuf)
201 {
202     int		i;
203     garray_T    ga;
204 
205     if (blob == NULL)
206     {
207 	*tofree = NULL;
208 	return (char_u *)"0z";
209     }
210 
211     // Store bytes in the growarray.
212     ga_init2(&ga, 1, 4000);
213     ga_concat(&ga, (char_u *)"0z");
214     for (i = 0; i < blob_len(blob); i++)
215     {
216 	if (i > 0 && (i & 3) == 0)
217 	    ga_concat(&ga, (char_u *)".");
218 	vim_snprintf((char *)numbuf, NUMBUFLEN, "%02X", (int)blob_get(blob, i));
219 	ga_concat(&ga, numbuf);
220     }
221     *tofree = ga.ga_data;
222     return *tofree;
223 }
224 
225 /*
226  * Convert a string variable, in the format of blob2string(), to a blob.
227  * Return NULL when conversion failed.
228  */
229     blob_T *
230 string2blob(char_u *str)
231 {
232     blob_T  *blob = blob_alloc();
233     char_u  *s = str;
234 
235     if (s[0] != '0' || (s[1] != 'z' && s[1] != 'Z'))
236 	goto failed;
237     s += 2;
238     while (vim_isxdigit(*s))
239     {
240 	if (!vim_isxdigit(s[1]))
241 	    goto failed;
242 	ga_append(&blob->bv_ga, (hex2nr(s[0]) << 4) + hex2nr(s[1]));
243 	s += 2;
244 	if (*s == '.' && vim_isxdigit(s[1]))
245 	    ++s;
246     }
247     if (*skipwhite(s) != NUL)
248 	goto failed;  // text after final digit
249 
250     ++blob->bv_refcount;
251     return blob;
252 
253 failed:
254     blob_free(blob);
255     return NULL;
256 }
257 
258 #endif /* defined(FEAT_EVAL) */
259