fileblob * fileblobCreate(void) { #ifdef CL_DEBUG fileblob *fb = (fileblob *)cli_calloc(1, sizeof(fileblob)); if(fb) fb->b.magic = BLOBCLASS; cli_dbgmsg("blobCreate\n"); return fb; #else return (fileblob *)cli_calloc(1, sizeof(fileblob)); #endif }
blob * blobCreate(void) { #ifdef CL_DEBUG blob *b = (blob *)cli_calloc(1, sizeof(blob)); if(b) b->magic = BLOBCLASS; cli_dbgmsg("blobCreate\n"); return b; #else return (blob *)cli_calloc(1, sizeof(blob)); #endif }
cli_events_t *cli_events_new(unsigned max_event) { struct cli_events *ev = cli_calloc(1, sizeof(*ev)); if (!ev) return NULL; ev->max = max_event; ev->events = cli_calloc(max_event, max_event * sizeof(*ev->events)); if (!ev->events) { free(ev); return NULL; } ev->errors.name = "errors"; ev->errors.type = ev_string; ev->errors.multiple = multiple_chain; return ev; }
int cli_addtypesigs(struct cl_engine *engine) { int i, ret; struct cli_matcher *root; if(!engine->root[0]) { cli_dbgmsg("cli_addtypesigs: Need to allocate AC trie in engine->root[0]\n"); root = engine->root[0] = (struct cli_matcher *) cli_calloc(1, sizeof(struct cli_matcher)); if(!root) { cli_errmsg("cli_addtypesigs: Can't initialise AC pattern matcher\n"); return CL_EMEM; } if((ret = cli_ac_init(root, cli_ac_mindepth, cli_ac_maxdepth))) { /* No need to free previously allocated memory here - all engine * elements will be properly freed by cl_free() */ cli_errmsg("cli_addtypesigs: Can't initialise AC pattern matcher\n"); return ret; } } else { root = engine->root[0]; } for(i = 0; cli_smagic[i].sig; i++) { if((ret = cli_parse_add(root, cli_smagic[i].descr, cli_smagic[i].sig, cli_smagic[i].type, NULL, 0))) { cli_errmsg("cli_addtypesigs: Problem adding signature for %s\n", cli_smagic[i].descr); return ret; } } return 0; }
END_TEST START_TEST (test_bm_scanbuff) { struct cli_matcher *root; const char *virname = NULL; int ret; root = (struct cli_matcher *) cli_calloc(1, sizeof(struct cli_matcher)); fail_unless(root != NULL, "root == NULL"); #ifdef USE_MPOOL root->mempool = mpool_create(); #endif ret = cli_bm_init(root); fail_unless(ret == CL_SUCCESS, "cli_bm_init() failed"); ret = cli_parse_add(root, "Sig1", "deadbabe", 0, 0, NULL, 0, NULL, 0); fail_unless(ret == CL_SUCCESS, "cli_parse_add() failed"); ret = cli_parse_add(root, "Sig2", "deadbeef", 0, 0, NULL, 0, NULL, 0); fail_unless(ret == CL_SUCCESS, "cli_parse_add() failed"); ret = cli_parse_add(root, "Sig3", "babedead", 0, 0, NULL, 0, NULL, 0); fail_unless(ret == CL_SUCCESS, "cli_parse_add() failed"); ret = cli_bm_scanbuff("blah\xde\xad\xbe\xef", 12, &virname, root, 0, 0, -1); fail_unless(ret == CL_VIRUS, "cli_bm_scanbuff() failed"); fail_unless(!strncmp(virname, "Sig2", 4), "Incorrect signature matched in cli_bm_scanbuff()\n"); cli_bm_free(root); #ifdef USE_MPOOL mpool_destroy(root->mempool); #endif free(root); }
int cli_LzmaInitUPX(CLI_LZMA **Lp, uint32_t dictsz) { CLI_LZMA *L = *Lp; if(!L) { *Lp = L = cli_calloc(sizeof(*L), 1); if(!L) { return LZMA_RESULT_DATA_ERROR; } } L->state.Properties.pb = 2; /* FIXME: these */ L->state.Properties.lp = 0; /* values may */ L->state.Properties.lc = 3; /* not be static */ L->state.Properties.DictionarySize = dictsz; if (!(L->state.Probs = (CProb *)cli_malloc(LzmaGetNumProbs(&L->state.Properties) * sizeof(CProb)))) return LZMA_RESULT_DATA_ERROR; if (!(L->state.Dictionary = (unsigned char *)cli_malloc(L->state.Properties.DictionarySize))) { free(L->state.Probs); return LZMA_RESULT_DATA_ERROR; } L->initted = 1; LzmaDecoderInit(&L->state); return LZMA_RESULT_OK; }
END_TEST START_TEST (test_pcre_scanbuff_allscan) { struct cli_ac_data mdata; struct cli_matcher *root; char *hexsig; unsigned int i, hexlen; int ret; root = ctx.engine->root[0]; fail_unless(root != NULL, "root == NULL"); #ifdef USE_MPOOL root->mempool = mpool_create(); #endif ret = cli_pcre_init(); fail_unless(ret == CL_SUCCESS, "[pcre] cli_pcre_init() failed"); for(i = 0; pcre_testdata[i].data; i++) { hexlen = strlen(PCRE_BYPASS) + strlen(pcre_testdata[i].hexsig) + 1; hexsig = cli_calloc(hexlen, sizeof(char)); fail_unless(hexsig != NULL, "[pcre] failed to prepend bypass (out-of-memory)"); strncat(hexsig, PCRE_BYPASS, hexlen); strncat(hexsig, pcre_testdata[i].hexsig, hexlen); ret = cli_parse_add(root, pcre_testdata[i].virname, hexsig, 0, 0, 0, pcre_testdata[i].offset, 0, NULL, 0); fail_unless(ret == CL_SUCCESS, "[pcre] cli_parse_add() failed"); free(hexsig); } ret = cli_pcre_build(root, CLI_DEFAULT_PCRE_MATCH_LIMIT, CLI_DEFAULT_PCRE_RECMATCH_LIMIT, NULL); fail_unless(ret == CL_SUCCESS, "[pcre] cli_pcre_build() failed"); // recomputate offsets ret = cli_ac_initdata(&mdata, root->ac_partsigs, root->ac_lsigs, root->ac_reloff_num, CLI_DEFAULT_AC_TRACKLEN); fail_unless(ret == CL_SUCCESS, "[pcre] cli_ac_initdata() failed"); ctx.options |= CL_SCAN_ALLMATCHES; for(i = 0; pcre_testdata[i].data; i++) { ret = cli_pcre_scanbuf((const unsigned char*)pcre_testdata[i].data, strlen(pcre_testdata[i].data), &virname, NULL, root, NULL, NULL, NULL); fail_unless_fmt(ret == pcre_testdata[i].expected_result, "[pcre] cli_pcre_scanbuff() failed for %s (%d != %d)", pcre_testdata[i].virname, ret, pcre_testdata[i].expected_result); if (pcre_testdata[i].expected_result == CL_VIRUS) fail_unless_fmt(!strncmp(virname, pcre_testdata[i].virname, strlen(pcre_testdata[i].virname)), "[pcre] Dataset %u matched with %s", i, virname); ret = cli_scanbuff((const unsigned char*)pcre_testdata[i].data, strlen(pcre_testdata[i].data), 0, &ctx, 0, NULL); fail_unless_fmt(ret == pcre_testdata[i].expected_result, "[pcre] cli_scanbuff() failed for %s", pcre_testdata[i].virname); /* num_virus field add to test case struct */ if (ctx.num_viruses) ctx.num_viruses = 0; } cli_ac_freedata(&mdata); }
static int onas_ddd_init_wdlt(uint64_t nwatches) { if (nwatches <= 0) return CL_EARG; wdlt = (char **) cli_calloc(nwatches << 1, sizeof(char*)); if (!wdlt) return CL_EMEM; wdlt_len = nwatches << 1; return CL_SUCCESS; }
void *__lzma_wrap_alloc(void *unused, size_t size) { UNUSEDPARAM(unused); if(!size || size > CLI_MAX_ALLOCATION) return NULL; if(!size || size > CLI_MAX_ALLOCATION) { cli_dbgmsg("lzma_wrap_alloc(): Attempt to allocate %lu bytes.\n", (unsigned long int) size); return NULL; } return cli_calloc(1, size); }
int cli_pcre_compile(struct cli_pcre_data *pd, long long unsigned match_limit, long long unsigned match_limit_recursion, unsigned int options, int opt_override) { const char *error; int erroffset; if (!pd || !pd->expression) { cli_errmsg("cli_pcre_compile: NULL pd or NULL pd->expression\n"); return CL_ENULLARG; } /* compile the pcre regex last arg is charset, allow for options override */ if (opt_override) pd->re = pcre_compile(pd->expression, options, &error, &erroffset, NULL); /* pd->re handled by pcre -> call pcre_free() -> calls free() */ else pd->re = pcre_compile(pd->expression, pd->options, &error, &erroffset, NULL); /* pd->re handled by pcre -> call pcre_free() -> calls free() */ if (pd->re == NULL) { cli_errmsg("cli_pcre_compile: PCRE compilation failed at offset %d: %s\n", erroffset, error); return CL_EMALFDB; } /* now study it... (section totally not from snort) */ pd->ex = pcre_study(pd->re, 0, &error); if (!(pd->ex)) { pd->ex = (pcre_extra *)cli_calloc(1, sizeof(*(pd->ex))); if (!(pd->ex)) { cli_errmsg("cli_pcre_compile: Unable to allocate memory for extra data\n"); return CL_EMEM; } } /* set the match limits */ if (pd->ex->flags & PCRE_EXTRA_MATCH_LIMIT) { pd->ex->match_limit = match_limit; } else { pd->ex->flags |= PCRE_EXTRA_MATCH_LIMIT; pd->ex->match_limit = match_limit; } /* set the recursion match limits */ #ifdef PCRE_EXTRA_MATCH_LIMIT_RECURSION if (pd->ex->flags & PCRE_EXTRA_MATCH_LIMIT_RECURSION) { pd->ex->match_limit_recursion = match_limit_recursion; } else { pd->ex->flags |= PCRE_EXTRA_MATCH_LIMIT_RECURSION; pd->ex->match_limit_recursion = match_limit_recursion; } #endif /* PCRE_EXTRA_MATCH_LIMIT_RECURSION */ /* non-dynamic allocated fields set by caller */ return CL_SUCCESS; }
static void pcre_perf_events_init(struct cli_pcre_meta *pm, const char *virname) { int ret; size_t namelen; if (!p_sigevents) { p_sigevents = cli_events_new(MAX_PCRE_SIGEVENT_ID); if (!p_sigevents) { cli_errmsg("pcre_perf: no memory for events table\n"); return; } } if (p_sigid > MAX_PCRE_SIGEVENT_ID - PCRE_EVENTS_PER_SIG - 1) { cli_errmsg("pcre_perf: events table full. Increase MAX_TRACKED_PCRE\n"); return; } if (!virname) { virname = "(null)"; namelen = 7; } else { namelen = strlen(virname)+strlen(pm->pdata.expression)+3; } /* set the name */ pm->statname = (char*)cli_calloc(1, namelen); if (!pm->statname) { return; } snprintf(pm->statname, namelen, "%s/%s/", virname, pm->pdata.expression); pm_dbgmsg("pcre_perf: adding sig ids starting %u for %s\n", p_sigid, pm->statname); /* register time event */ pm->sigtime_id = p_sigid; ret = cli_event_define(p_sigevents, p_sigid++, pm->statname, ev_time, multiple_sum); if (ret) { cli_errmsg("pcre_perf: cli_event_define() error for time event id %d\n", pm->sigtime_id); pm->sigtime_id = MAX_PCRE_SIGEVENT_ID+1; return; } /* register match count */ pm->sigmatch_id = p_sigid; ret = cli_event_define(p_sigevents, p_sigid++, pm->statname, ev_int, multiple_sum); if (ret) { cli_errmsg("pcre_perf: cli_event_define() error for matches event id %d\n", pm->sigmatch_id); pm->sigmatch_id = MAX_PCRE_SIGEVENT_ID+1; return; } }
struct uniq *uniq_init(uint32_t count) { struct uniq *U; if(!count) return NULL; U = cli_calloc(1, sizeof(*U)); if(!U) return NULL; U->md5s = cli_malloc(count * sizeof(*U->md5s)); if(!U->md5s) { uniq_free(U); return NULL; } return U; }
int hashtab_init(struct hashtable *s,size_t capacity) { if(!s) return CL_ENULLARG; PROFILE_INIT(s); capacity = get_nearest_capacity(capacity); s->htable = cli_calloc(capacity,sizeof(*s->htable)); if(!s->htable) return CL_EMEM; s->capacity = capacity; s->used = 0; s->maxfill = 8*capacity/10; return 0; }
static struct scope* scope_new(struct parser_state *state) { struct scope *parent = state->current; struct scope *s = cli_calloc(1, sizeof(*s)); if(!s) return NULL; if(cli_hashtab_init(&s->id_map, 10) < 0) { free(s); return NULL; } s->parent = parent; s->fsm_state = Base; s->nxt = state->list; state->list = s; state->current = s; return s; }
char *cli_str2hex(const char *string, unsigned int len) { char *hexstr; char HEX[] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' }; unsigned int i, j; if((hexstr = (char *) cli_calloc(2 * len + 1, sizeof(char))) == NULL) return NULL; for(i = 0, j = 0; i < len; i++, j += 2) { hexstr[j] = HEX[(string[i] >> 4) & 0xf]; hexstr[j + 1] = HEX[string[i] & 0xf]; } return hexstr; }
static int hashtab_grow(struct hashtable *s) { const size_t new_capacity = get_nearest_capacity(s->capacity); struct element* htable = cli_calloc(new_capacity, sizeof(*s->htable)); size_t i,idx, used = 0; if(new_capacity == s->capacity || !htable) return CL_EMEM; PROFILE_GROW_START(s); cli_dbgmsg("hashtab.c: Warning: growing open-addressing hashtables is slow. Either allocate more storage when initializing, or use other hashtable types!\n"); for(i=0; i < s->capacity;i++) { if(s->htable[i].key && s->htable[i].key != DELETED_KEY) { struct element* element; size_t tries = 1; PROFILE_CALC_HASH(s); idx = hash(s->htable[i].key, strlen((const char*)s->htable[i].key), new_capacity); element = &htable[idx]; while(element->key && tries <= new_capacity) { idx = (idx + tries++) % new_capacity; element = &htable[idx]; } if(!element->key) { /* copy element from old hashtable to new */ PROFILE_GROW_FOUND(s, tries); *element = s->htable[i]; used++; } else { cli_errmsg("hashtab.c: Impossible - unable to rehash table"); return CL_EMEM;/* this means we didn't find enough room for all elements in the new table, should never happen */ } } } free(s->htable); s->htable = htable; s->used = used; s->capacity = new_capacity; s->maxfill = new_capacity*8/10; cli_dbgmsg("Table %p size after grow:%ld\n",(void*)s,s->capacity); PROFILE_GROW_DONE(s); return CL_SUCCESS; }
struct parser_state *cli_js_init(void) { struct parser_state *state = cli_calloc(1, sizeof(*state)); if(!state) return NULL; if(!scope_new(state)) { free(state); return NULL; } state->global = state->current; if(yylex_init(&state->scanner)) { scope_done(state->global); free(state); return NULL; } cli_dbgmsg(MODULE "cli_js_init() done\n"); return state; }
static int openioc_parse_content(xmlTextReaderPtr reader, struct openioc_hash ** elems, int context_hash) { const xmlChar * xmlval; struct openioc_hash * elem; int rc = CL_SUCCESS; if (context_hash == 0) { xmlChar * type = xmlTextReaderGetAttribute(reader, (const xmlChar *)"type"); if (type == NULL) { cli_dbgmsg("openioc_parse: xmlTextReaderGetAttribute no type attribute " "for <Content> element\n"); return rc; } else { if (xmlStrcasecmp(type, (const xmlChar *)"sha1") && xmlStrcasecmp(type, (const xmlChar *)"sha256") && xmlStrcasecmp(type, (const xmlChar *)"md5")) { xmlFree(type); return rc; } } xmlFree(type); } if (xmlTextReaderRead(reader) == 1 && xmlTextReaderNodeType(reader) == XML_READER_TYPE_TEXT) { xmlval = xmlTextReaderConstValue(reader); if (xmlval) { elem = cli_calloc(1, sizeof(struct openioc_hash)); if (NULL == elem) { cli_dbgmsg("openioc_parse: calloc fails for openioc_hash.\n"); return CL_EMEM; } elem->hash = xmlStrdup(xmlval); elem->next = *elems; *elems = elem; } else { cli_dbgmsg("openioc_parse: xmlTextReaderConstValue() returns NULL for Content md5 value.\n"); } } else { cli_dbgmsg("openioc_parse: No text for XML Content element.\n"); } return rc; }
short int *cli_hex2si(const char *hex) { short int *str, *ptr, val, c; int i, len; len = strlen(hex); if(len % 2 != 0) { cli_errmsg("cli_hex2si(): Malformed hexstring: %s (length: %d)\n", hex, len); return NULL; } str = cli_calloc((len / 2) + 1, sizeof(short int)); if(!str) return NULL; ptr = str; for(i = 0; i < len; i += 2) { if(hex[i] == '?') { val = CLI_IGN; } else if(hex[i] == '@') { val = CLI_ALT; } else { if((c = cli_hex2int(hex[i])) >= 0) { val = c; if((c = cli_hex2int(hex[i+1])) >= 0) { val = (val << 4) + c; } else { free(str); return NULL; } } else { free(str); return NULL; } } *ptr++ = val; } return str; }
extern cl_fmap_t *cl_fmap_open_memory(const void *start, size_t len) { int pgsz = cli_getpagesize(); cl_fmap_t *m = cli_calloc(1, sizeof(*m)); if (!m) { cli_warnmsg("fmap: map allocation failed\n"); return NULL; } m->data = start; m->len = len; m->real_len = len; m->pgsz = pgsz; m->pages = fmap_align_items(len, pgsz); m->unmap = unmap_malloc; m->need = mem_need; m->need_offstr = mem_need_offstr; m->gets = mem_gets; m->unneed_off = mem_unneed_off; return m; }
unsigned char *cli_decodesig(const char *sig, unsigned int plen, mp_int e, mp_int n) { int i, slen = strlen(sig), dec; unsigned char *plain; mp_int r, p, c; mp_init(&r); mp_init(&c); for(i = 0; i < slen; i++) { if((dec = cli_ndecode(sig[i])) < 0) { mp_clear(&r); mp_clear(&c); return NULL; } mp_set_int(&r, dec); mp_mul_2d(&r, 6 * i, &r); mp_add(&r, &c, &c); } plain = (unsigned char *) cli_calloc(plen + 1, sizeof(unsigned char)); if(!plain) { cli_errmsg("cli_decodesig: Can't allocate memory for 'plain'\n"); mp_clear(&r); mp_clear(&c); return NULL; } mp_init(&p); mp_exptmod(&c, &e, &n, &p); /* plain = cipher^e mod n */ mp_clear(&c); mp_set_int(&c, 256); for(i = plen - 1; i >= 0; i--) { /* reverse */ mp_div(&p, &c, &p, &r); plain[i] = mp_get_int(&r); } mp_clear(&c); mp_clear(&p); mp_clear(&r); return plain; }
int lzwInit(lzw_streamp strm) { struct lzw_internal_state *state; hcode_t code; state = cli_malloc(sizeof(struct lzw_internal_state)); if (state == NULL) { strm->msg = "failed to allocate state"; return LZW_MEM_ERROR; } /* general state setup */ state->nbits = BITS_MIN; state->nextdata = 0; state->nextbits = 0; /* dictionary setup */ state->dec_codetab = cli_calloc(CSIZE, sizeof(code_t)); if (state->dec_codetab == NULL) { free(state); strm->msg = "failed to allocate code table"; return LZW_MEM_ERROR; } for (code = 0; code < CODE_BASIC; code++) { state->dec_codetab[code].next = NULL; state->dec_codetab[code].length = 1; state->dec_codetab[code].value = code; state->dec_codetab[code].firstchar = code; } state->dec_restart = 0; state->dec_nbitsmask = MAXCODE(BITS_MIN); state->dec_free_entp = state->dec_codetab + CODE_FIRST; state->dec_oldcodep = &state->dec_codetab[CODE_CLEAR]; state->dec_maxcodep = &state->dec_codetab[state->dec_nbitsmask-1]; strm->state = state; return LZW_OK; }
int cli_xtoi(const char *hex) { int len, val, i; char * hexbuf; len = strlen(hex); if(len % 2 == 0) return cli_hex2num(hex); hexbuf = cli_calloc(len+2, sizeof(char)); if (hexbuf == NULL) { cli_errmsg("cli_xtoi(): cli_malloc fails.\n"); return -1; } for(i = 0; i < len; i++) hexbuf[i+1] = hex[i]; val = cli_hex2num(hexbuf); free(hexbuf); return val; }
char *cli_hex2str(const char *hex) { char *str; size_t len; len = strlen(hex); if(len % 2 != 0) { cli_errmsg("cli_hex2str(): Malformed hexstring: %s (length: %u)\n", hex, (unsigned)len); return NULL; } str = cli_calloc((len / 2) + 1, sizeof(char)); if(!str) return NULL; if (cli_hex2str_to(hex, str, len) == -1) { free(str); return NULL; } return str; }
uint16_t *cli_hex2ui(const char *hex) { uint16_t *str; unsigned int len; len = strlen(hex); if(len % 2 != 0) { cli_errmsg("cli_hex2ui(): Malformed hexstring: %s (length: %u)\n", hex, len); return NULL; } str = cli_calloc((len / 2) + 1, sizeof(uint16_t)); if(!str) return NULL; if(cli_realhex2ui(hex, str, len)) return str; free(str); return NULL; }
int cli_LzmaInit(CLI_LZMA **Lp, uint64_t size_override) { CLI_LZMA *L = *Lp; if(!L) { *Lp = L = cli_calloc(sizeof(*L), 1); if(!L) { return CL_EMEM; } } L->initted = 0; if(size_override) L->usize=size_override; if (!L->next_in || L->avail_in < LZMA_PROPERTIES_SIZE + 8) return LZMA_RESULT_OK; if (LzmaDecodeProperties(&L->state.Properties, L->next_in, LZMA_PROPERTIES_SIZE) != LZMA_RESULT_OK) return LZMA_RESULT_DATA_ERROR; L->next_in += LZMA_PROPERTIES_SIZE; L->avail_in -= LZMA_PROPERTIES_SIZE; if (!L->usize) { L->usize=(uint64_t)cli_readint32(L->next_in) + ((uint64_t)cli_readint32(L->next_in+4)<<32); L->next_in += 8; L->avail_in -= 8; } if (!(L->state.Probs = (CProb *)cli_malloc(LzmaGetNumProbs(&L->state.Properties) * sizeof(CProb)))) return LZMA_RESULT_DATA_ERROR; if (!(L->state.Dictionary = (unsigned char *)cli_malloc(L->state.Properties.DictionarySize))) { free(L->state.Probs); return LZMA_RESULT_DATA_ERROR; } L->initted = 1; LzmaDecoderInit(&L->state); return LZMA_RESULT_OK; }
int cli_bm_init(struct cl_node *root) { unsigned int i; unsigned int size = DHASH(256, 256, 256); cli_dbgmsg("in cli_bm_init()\n"); cli_dbgmsg("BM: Number of indexes = %d\n", size); if(!(root->bm_shift = (int *) cli_malloc(size * sizeof(int)))) return CL_EMEM; if(!(root->bm_suffix = (struct cli_bm_patt **) cli_calloc(size, sizeof(struct cli_bm_patt *)))) { free(root->bm_shift); return CL_EMEM; } for(i = 0; i < size; i++) root->bm_shift[i] = BM_MIN_LENGTH - BM_BLOCK_SIZE + 1; return 0; }
static void code_print(code_t *code) { code_t *cpt = code; uint8_t *string; int i = 0; string = cli_calloc(code->length+1, sizeof(uint8_t)); if (!string) return; while (cpt && (i < code->length)) { if (isalnum(cpt->value)) string[code->length - i - 1] = cpt->value; else string[code->length - i - 1] = '*'; i++; cpt = cpt->next; } printf("%s\n", string); free(string); }
int32_t cli_bcapi_buffer_pipe_new(struct cli_bc_ctx *ctx, uint32_t size) { unsigned char *data; struct bc_buffer *b; unsigned n = ctx->nbuffers + 1; data = cli_calloc(1, size); if (!data) return -1; b = cli_realloc(ctx->buffers, sizeof(*ctx->buffers)*n); if (!b) { free(data); return -1; } ctx->buffers = b; ctx->nbuffers = n; b = &b[n-1]; b->data = data; b->size = size; b->write_cursor = b->read_cursor = 0; return n-1; }
char *cli_utf16toascii(const char *str, unsigned int length) { char *decoded; unsigned int i, j; if(length < 2) { cli_dbgmsg("cli_utf16toascii: length < 2\n"); return NULL; } if(length % 2) length--; if(!(decoded = cli_calloc(length / 2 + 1, sizeof(char)))) return NULL; for(i = 0, j = 0; i < length; i += 2, j++) { decoded[j] = str[i + 1] << 4; decoded[j] += str[i]; } return decoded; }