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 *
blob_alloc(void)23 blob_alloc(void)
24 {
25 blob_T *blob = ALLOC_CLEAR_ONE(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
rettv_blob_alloc(typval_T * rettv)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
rettv_blob_set(typval_T * rettv,blob_T * b)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
blob_copy(blob_T * from,typval_T * to)61 blob_copy(blob_T *from, typval_T *to)
62 {
63 int ret = OK;
64
65 to->v_type = VAR_BLOB;
66 to->v_lock = 0;
67 if (from == NULL)
68 to->vval.v_blob = NULL;
69 else if (rettv_blob_alloc(to) == FAIL)
70 ret = FAIL;
71 else
72 {
73 int len = from->bv_ga.ga_len;
74
75 if (len > 0)
76 {
77 to->vval.v_blob->bv_ga.ga_data =
78 vim_memsave(from->bv_ga.ga_data, len);
79 if (to->vval.v_blob->bv_ga.ga_data == NULL)
80 len = 0;
81 }
82 to->vval.v_blob->bv_ga.ga_len = len;
83 to->vval.v_blob->bv_ga.ga_maxlen = len;
84 }
85 return ret;
86 }
87
88 void
blob_free(blob_T * b)89 blob_free(blob_T *b)
90 {
91 ga_clear(&b->bv_ga);
92 vim_free(b);
93 }
94
95 /*
96 * Unreference a blob: decrement the reference count and free it when it
97 * becomes zero.
98 */
99 void
blob_unref(blob_T * b)100 blob_unref(blob_T *b)
101 {
102 if (b != NULL && --b->bv_refcount <= 0)
103 blob_free(b);
104 }
105
106 /*
107 * Get the length of data.
108 */
109 long
blob_len(blob_T * b)110 blob_len(blob_T *b)
111 {
112 if (b == NULL)
113 return 0L;
114 return b->bv_ga.ga_len;
115 }
116
117 /*
118 * Get byte "idx" in blob "b".
119 * Caller must check that "idx" is valid.
120 */
121 int
blob_get(blob_T * b,int idx)122 blob_get(blob_T *b, int idx)
123 {
124 return ((char_u*)b->bv_ga.ga_data)[idx];
125 }
126
127 /*
128 * Store one byte "byte" in blob "blob" at "idx".
129 * Caller must make sure that "idx" is valid.
130 */
131 void
blob_set(blob_T * blob,int idx,int byte)132 blob_set(blob_T *blob, int idx, int byte)
133 {
134 ((char_u*)blob->bv_ga.ga_data)[idx] = byte;
135 }
136
137 /*
138 * Store one byte "byte" in blob "blob" at "idx".
139 * Append one byte if needed.
140 */
141 void
blob_set_append(blob_T * blob,int idx,int byte)142 blob_set_append(blob_T *blob, int idx, int byte)
143 {
144 garray_T *gap = &blob->bv_ga;
145
146 // Allow for appending a byte. Setting a byte beyond
147 // the end is an error otherwise.
148 if (idx < gap->ga_len
149 || (idx == gap->ga_len && ga_grow(gap, 1) == OK))
150 {
151 blob_set(blob, idx, byte);
152 if (idx == gap->ga_len)
153 ++gap->ga_len;
154 }
155 }
156
157 /*
158 * Return TRUE when two blobs have exactly the same values.
159 */
160 int
blob_equal(blob_T * b1,blob_T * b2)161 blob_equal(
162 blob_T *b1,
163 blob_T *b2)
164 {
165 int i;
166 int len1 = blob_len(b1);
167 int len2 = blob_len(b2);
168
169 // empty and NULL are considered the same
170 if (len1 == 0 && len2 == 0)
171 return TRUE;
172 if (b1 == b2)
173 return TRUE;
174 if (len1 != len2)
175 return FALSE;
176
177 for (i = 0; i < b1->bv_ga.ga_len; i++)
178 if (blob_get(b1, i) != blob_get(b2, i)) return FALSE;
179 return TRUE;
180 }
181
182 /*
183 * Read "blob" from file "fd".
184 * Return OK or FAIL.
185 */
186 int
read_blob(FILE * fd,blob_T * blob)187 read_blob(FILE *fd, blob_T *blob)
188 {
189 struct stat st;
190
191 if (fstat(fileno(fd), &st) < 0)
192 return FAIL;
193 if (ga_grow(&blob->bv_ga, st.st_size) == FAIL)
194 return FAIL;
195 blob->bv_ga.ga_len = st.st_size;
196 if (fread(blob->bv_ga.ga_data, 1, blob->bv_ga.ga_len, fd)
197 < (size_t)blob->bv_ga.ga_len)
198 return FAIL;
199 return OK;
200 }
201
202 /*
203 * Write "blob" to file "fd".
204 * Return OK or FAIL.
205 */
206 int
write_blob(FILE * fd,blob_T * blob)207 write_blob(FILE *fd, blob_T *blob)
208 {
209 if (fwrite(blob->bv_ga.ga_data, 1, blob->bv_ga.ga_len, fd)
210 < (size_t)blob->bv_ga.ga_len)
211 {
212 emsg(_(e_write));
213 return FAIL;
214 }
215 return OK;
216 }
217
218 /*
219 * Convert a blob to a readable form: "0z00112233.44556677.8899"
220 */
221 char_u *
blob2string(blob_T * blob,char_u ** tofree,char_u * numbuf)222 blob2string(blob_T *blob, char_u **tofree, char_u *numbuf)
223 {
224 int i;
225 garray_T ga;
226
227 if (blob == NULL)
228 {
229 *tofree = NULL;
230 return (char_u *)"0z";
231 }
232
233 // Store bytes in the growarray.
234 ga_init2(&ga, 1, 4000);
235 ga_concat(&ga, (char_u *)"0z");
236 for (i = 0; i < blob_len(blob); i++)
237 {
238 if (i > 0 && (i & 3) == 0)
239 ga_concat(&ga, (char_u *)".");
240 vim_snprintf((char *)numbuf, NUMBUFLEN, "%02X", (int)blob_get(blob, i));
241 ga_concat(&ga, numbuf);
242 }
243 *tofree = ga.ga_data;
244 return *tofree;
245 }
246
247 /*
248 * Convert a string variable, in the format of blob2string(), to a blob.
249 * Return NULL when conversion failed.
250 */
251 blob_T *
string2blob(char_u * str)252 string2blob(char_u *str)
253 {
254 blob_T *blob = blob_alloc();
255 char_u *s = str;
256
257 if (blob == NULL)
258 return NULL;
259 if (s[0] != '0' || (s[1] != 'z' && s[1] != 'Z'))
260 goto failed;
261 s += 2;
262 while (vim_isxdigit(*s))
263 {
264 if (!vim_isxdigit(s[1]))
265 goto failed;
266 ga_append(&blob->bv_ga, (hex2nr(s[0]) << 4) + hex2nr(s[1]));
267 s += 2;
268 if (*s == '.' && vim_isxdigit(s[1]))
269 ++s;
270 }
271 if (*skipwhite(s) != NUL)
272 goto failed; // text after final digit
273
274 ++blob->bv_refcount;
275 return blob;
276
277 failed:
278 blob_free(blob);
279 return NULL;
280 }
281
282 int
blob_slice_or_index(blob_T * blob,int is_range,varnumber_T n1,varnumber_T n2,int exclusive,typval_T * rettv)283 blob_slice_or_index(
284 blob_T *blob,
285 int is_range,
286 varnumber_T n1,
287 varnumber_T n2,
288 int exclusive,
289 typval_T *rettv)
290 {
291 long len = blob_len(blob);
292
293 if (is_range)
294 {
295 // The resulting variable is a sub-blob. If the indexes
296 // are out of range the result is empty.
297 if (n1 < 0)
298 {
299 n1 = len + n1;
300 if (n1 < 0)
301 n1 = 0;
302 }
303 if (n2 < 0)
304 n2 = len + n2;
305 else if (n2 >= len)
306 n2 = len - (exclusive ? 0 : 1);
307 if (exclusive)
308 --n2;
309 if (n1 >= len || n2 < 0 || n1 > n2)
310 {
311 clear_tv(rettv);
312 rettv->v_type = VAR_BLOB;
313 rettv->vval.v_blob = NULL;
314 }
315 else
316 {
317 blob_T *new_blob = blob_alloc();
318 long i;
319
320 if (new_blob != NULL)
321 {
322 if (ga_grow(&new_blob->bv_ga, n2 - n1 + 1) == FAIL)
323 {
324 blob_free(new_blob);
325 return FAIL;
326 }
327 new_blob->bv_ga.ga_len = n2 - n1 + 1;
328 for (i = n1; i <= n2; i++)
329 blob_set(new_blob, i - n1, blob_get(blob, i));
330
331 clear_tv(rettv);
332 rettv_blob_set(rettv, new_blob);
333 }
334 }
335 }
336 else
337 {
338 // The resulting variable is a byte value.
339 // If the index is too big or negative that is an error.
340 if (n1 < 0)
341 n1 = len + n1;
342 if (n1 < len && n1 >= 0)
343 {
344 int v = blob_get(blob, n1);
345
346 clear_tv(rettv);
347 rettv->v_type = VAR_NUMBER;
348 rettv->vval.v_number = v;
349 }
350 else
351 {
352 semsg(_(e_blobidx), n1);
353 return FAIL;
354 }
355 }
356 return OK;
357 }
358
359 /*
360 * Check if "n1"- is a valid index for a blobl with length "bloblen".
361 */
362 int
check_blob_index(long bloblen,varnumber_T n1,int quiet)363 check_blob_index(long bloblen, varnumber_T n1, int quiet)
364 {
365 if (n1 < 0 || n1 > bloblen)
366 {
367 if (!quiet)
368 semsg(_(e_blobidx), n1);
369 return FAIL;
370 }
371 return OK;
372 }
373
374 /*
375 * Check if "n1"-"n2" is a valid range for a blob with length "bloblen".
376 */
377 int
check_blob_range(long bloblen,varnumber_T n1,varnumber_T n2,int quiet)378 check_blob_range(long bloblen, varnumber_T n1, varnumber_T n2, int quiet)
379 {
380 if (n2 < 0 || n2 >= bloblen || n2 < n1)
381 {
382 if (!quiet)
383 semsg(_(e_blobidx), n2);
384 return FAIL;
385 }
386 return OK;
387 }
388
389 /*
390 * Set bytes "n1" to "n2" (inclusive) in "dest" to the value of "src".
391 * Caller must make sure "src" is a blob.
392 * Returns FAIL if the number of bytes does not match.
393 */
394 int
blob_set_range(blob_T * dest,long n1,long n2,typval_T * src)395 blob_set_range(blob_T *dest, long n1, long n2, typval_T *src)
396 {
397 int il, ir;
398
399 if (n2 - n1 + 1 != blob_len(src->vval.v_blob))
400 {
401 emsg(_("E972: Blob value does not have the right number of bytes"));
402 return FAIL;
403 }
404
405 ir = 0;
406 for (il = n1; il <= n2; il++)
407 blob_set(dest, il, blob_get(src->vval.v_blob, ir++));
408 return OK;
409 }
410
411 /*
412 * "remove({blob})" function
413 */
414 void
blob_remove(typval_T * argvars,typval_T * rettv,char_u * arg_errmsg)415 blob_remove(typval_T *argvars, typval_T *rettv, char_u *arg_errmsg)
416 {
417 blob_T *b = argvars[0].vval.v_blob;
418 int error = FALSE;
419 long idx;
420 long end;
421
422 if (b != NULL && value_check_lock(b->bv_lock, arg_errmsg, TRUE))
423 return;
424
425 idx = (long)tv_get_number_chk(&argvars[1], &error);
426 if (!error)
427 {
428 int len = blob_len(b);
429 char_u *p;
430
431 if (idx < 0)
432 // count from the end
433 idx = len + idx;
434 if (idx < 0 || idx >= len)
435 {
436 semsg(_(e_blobidx), idx);
437 return;
438 }
439 if (argvars[2].v_type == VAR_UNKNOWN)
440 {
441 // Remove one item, return its value.
442 p = (char_u *)b->bv_ga.ga_data;
443 rettv->vval.v_number = (varnumber_T) *(p + idx);
444 mch_memmove(p + idx, p + idx + 1, (size_t)len - idx - 1);
445 --b->bv_ga.ga_len;
446 }
447 else
448 {
449 blob_T *blob;
450
451 // Remove range of items, return blob with values.
452 end = (long)tv_get_number_chk(&argvars[2], &error);
453 if (error)
454 return;
455 if (end < 0)
456 // count from the end
457 end = len + end;
458 if (end >= len || idx > end)
459 {
460 semsg(_(e_blobidx), end);
461 return;
462 }
463 blob = blob_alloc();
464 if (blob == NULL)
465 return;
466 blob->bv_ga.ga_len = end - idx + 1;
467 if (ga_grow(&blob->bv_ga, end - idx + 1) == FAIL)
468 {
469 vim_free(blob);
470 return;
471 }
472 p = (char_u *)b->bv_ga.ga_data;
473 mch_memmove((char_u *)blob->bv_ga.ga_data, p + idx,
474 (size_t)(end - idx + 1));
475 ++blob->bv_refcount;
476 rettv->v_type = VAR_BLOB;
477 rettv->vval.v_blob = blob;
478
479 if (len - end - 1 > 0)
480 mch_memmove(p + idx, p + end + 1, (size_t)(len - end - 1));
481 b->bv_ga.ga_len -= end - idx + 1;
482 }
483 }
484 }
485
486 /*
487 * blob2list() function
488 */
489 void
f_blob2list(typval_T * argvars,typval_T * rettv)490 f_blob2list(typval_T *argvars, typval_T *rettv)
491 {
492 blob_T *blob;
493 list_T *l;
494 int i;
495
496 if (rettv_list_alloc(rettv) == FAIL)
497 return;
498
499 if (check_for_blob_arg(argvars, 0) == FAIL)
500 return;
501
502 blob = argvars->vval.v_blob;
503 l = rettv->vval.v_list;
504 for (i = 0; i < blob_len(blob); i++)
505 list_append_number(l, blob_get(blob, i));
506 }
507
508 /*
509 * list2blob() function
510 */
511 void
f_list2blob(typval_T * argvars,typval_T * rettv)512 f_list2blob(typval_T *argvars, typval_T *rettv)
513 {
514 list_T *l;
515 listitem_T *li;
516 blob_T *blob;
517
518 if (rettv_blob_alloc(rettv) == FAIL)
519 return;
520 blob = rettv->vval.v_blob;
521
522 if (check_for_list_arg(argvars, 0) == FAIL)
523 return;
524
525 l = argvars->vval.v_list;
526 if (l == NULL)
527 return;
528
529 CHECK_LIST_MATERIALIZE(l);
530 FOR_ALL_LIST_ITEMS(l, li)
531 {
532 int error;
533 varnumber_T n;
534
535 error = FALSE;
536 n = tv_get_number_chk(&li->li_tv, &error);
537 if (error == TRUE || n < 0 || n > 255)
538 {
539 if (!error)
540 semsg(_(e_invalid_value_for_blob_nr), n);
541 ga_clear(&blob->bv_ga);
542 return;
543 }
544 ga_append(&blob->bv_ga, n);
545 }
546 }
547
548 #endif // defined(FEAT_EVAL)
549