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 = 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 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(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 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 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 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 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 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 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 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 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 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 * 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 * 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 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 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 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 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 415 blob_remove(typval_T *argvars, typval_T *rettv) 416 { 417 int error = FALSE; 418 long idx = (long)tv_get_number_chk(&argvars[1], &error); 419 long end; 420 421 if (!error) 422 { 423 blob_T *b = argvars[0].vval.v_blob; 424 int len = blob_len(b); 425 char_u *p; 426 427 if (idx < 0) 428 // count from the end 429 idx = len + idx; 430 if (idx < 0 || idx >= len) 431 { 432 semsg(_(e_blobidx), idx); 433 return; 434 } 435 if (argvars[2].v_type == VAR_UNKNOWN) 436 { 437 // Remove one item, return its value. 438 p = (char_u *)b->bv_ga.ga_data; 439 rettv->vval.v_number = (varnumber_T) *(p + idx); 440 mch_memmove(p + idx, p + idx + 1, (size_t)len - idx - 1); 441 --b->bv_ga.ga_len; 442 } 443 else 444 { 445 blob_T *blob; 446 447 // Remove range of items, return blob with values. 448 end = (long)tv_get_number_chk(&argvars[2], &error); 449 if (error) 450 return; 451 if (end < 0) 452 // count from the end 453 end = len + end; 454 if (end >= len || idx > end) 455 { 456 semsg(_(e_blobidx), end); 457 return; 458 } 459 blob = blob_alloc(); 460 if (blob == NULL) 461 return; 462 blob->bv_ga.ga_len = end - idx + 1; 463 if (ga_grow(&blob->bv_ga, end - idx + 1) == FAIL) 464 { 465 vim_free(blob); 466 return; 467 } 468 p = (char_u *)b->bv_ga.ga_data; 469 mch_memmove((char_u *)blob->bv_ga.ga_data, p + idx, 470 (size_t)(end - idx + 1)); 471 ++blob->bv_refcount; 472 rettv->v_type = VAR_BLOB; 473 rettv->vval.v_blob = blob; 474 475 if (len - end - 1 > 0) 476 mch_memmove(p + idx, p + end + 1, (size_t)(len - end - 1)); 477 b->bv_ga.ga_len -= end - idx + 1; 478 } 479 } 480 } 481 482 #endif // defined(FEAT_EVAL) 483