packet build_packet(int sz, char * data) { int escapes = count_escapes(sz, data); int i, offset; packet res; res.sz = sz + escapes + OVERHEAD; res.data = (unsigned char*)malloc(res.sz); /* TODO: escape size bytes and checksum */ res.data[0] = 0x7E; res.data[1] = (sz >> 8) & 0xFF; res.data[2] = sz & 0xFF; char checksum = 0; offset = 3; for( i = 0; i < sz; i++ ) { if( is_escape(data[i]) ) { res.data[i + offset] = 0x7D; offset++; res.data[i + offset] = data[i] ^ 0x20; } else { res.data[i + offset] = data[i]; } checksum += data[i]; } checksum = 0xFF - checksum; res.data[i + offset] = checksum; return res; }
/* Expands escape sequences within a string * * src must be a string with a NUL terminator * * NUL characters are not expanded to \0 (otherwise how would we know when * the input string ends?) * * Adapted from http://stackoverflow.com/questions/3535023/convert-characters-in-a-c-string-to-their-escape-sequences */ char *expand_escapes(const char* src) { char* dest; char* d; if ((src == NULL) || ( strlen(src) == 0)) { dest = malloc(sizeof(char)); d = dest; } else { // escaped lengths must take NUL terminator into account int dest_len = strlen(src) + count_escapes(src) + 1; dest = malloc(dest_len * sizeof(char)); d = dest; char c = *(src++); while (c) { switch(c) { case '\\': *(d++) = '\\'; *(d++) = '\\'; break; case '\"': *(d++) = '\\'; *(d++) = '\"'; break; default: *(d++) = c; } c = *(src++); } } *d = '\0'; /* Ensure NUL terminator */ return(dest); }
/* * escape_to_html */ VALUE escape_to_html(VALUE self, VALUE rawdata) { VALUE result; if (rawdata == Qnil) { return rb_str_new2(""); } if (TYPE(rawdata) != T_STRING) { rb_raise(rb_eTypeError, "invalid type for rawdata"); return Qnil; } char *dataStr = StringValueCStr(rawdata); size_t dataStrLen = strlen(dataStr); char code[CODE_BUF_SIZE]; bool inCode = false; size_t in_pos = 0, scratch_pos = 0, code_pos = 0; /* * Pre alloc scratch space that's at least as big as the input string, plus * some space for inserted span elements. * * Every string gets wrapped in a <span class="ansible_none"></span> * * Assume that every new escape code that's encountered will produce open * and close span tags that together consume 100 bytes (this allows for 3-5 * codes per span, which is generous). This should be good enough for * pretty much everything. If it's not, we'll still notice when we run out * of space and try to realloc. */ int spans = 1 + count_escapes(dataStr, dataStrLen); size_t scratchLen = dataStrLen + (spans * MAX_SPAN_SIZE); char *scratch = malloc(scratchLen); memset(scratch, 0, scratchLen); write_scratch((char *)SPAN_START(ansible_none), sizeof(SPAN_START(ansible_none))-1, &scratch, &scratch_pos, &scratchLen); for (; in_pos < dataStrLen; in_pos++) { char c = dataStr[in_pos]; /* * Copy characters into scratch that arent within an escape code block. */ if (c == '\033') { // Enter escape code on ^[ inCode = true; code_pos = 0; } else if (c == 'm') { if (inCode) { // Exit escape code on m inCode = false; code[code_pos] = 0; DBG("code: %s\n", code); write_span(code, &scratch, &scratch_pos, &scratchLen); } else { // Copy an m that's not terminating an escape code write_scratch(&c, 1, &scratch, &scratch_pos, &scratchLen); } } else if (!inCode) { // Copy everything else write_scratch(&c, 1, &scratch, &scratch_pos, &scratchLen); } else { // fill code buffer if (code_pos < sizeof(code)) { code[code_pos++] = c; } } } write_scratch((char *)SPAN_CLOSE, sizeof(SPAN_CLOSE)-1, &scratch, &scratch_pos, &scratchLen); result = rb_enc_str_new(scratch, scratch_pos, rb_enc_find("BINARY")); free(scratch); return result; }