void utf8_regression_1(void) { uint32_t i; unsigned valid = 0; for (i = 0; i < 0xffffffffUL; i++) { static char data[5]; static char hit[0x10FFFFU + 1]; uint32_t d; if (0 == (i % (((uint32_t) -1) / 100))) { printf("i=%u\n", i / (((uint32_t) -1) / 100)); } poke_be32(data, i); d = utf8_decode(data, 4); if ((uint32_t) -1 == d) continue; if (d > 0x10ffffU || utf32_is_non_character(d) || utf32_is_surrogate(d)) { printf("data: %02x %02x %02x %02x\n", (unsigned char) data[0], (unsigned char) data[1], (unsigned char) data[2], (unsigned char) data[3]); printf("d: U+%lx\n", (unsigned long) d); printf("i: %lu\n", (unsigned long) i); RUNTIME_ASSERT(d <= 0x10ffffU); RUNTIME_ASSERT(!utf32_is_non_character(d)); RUNTIME_ASSERT(!utf32_is_surrogate(d)); } if (!hit[d]) { hit[d] = 1; valid++; } { unsigned n; char buf[4]; n = utf8_encode(d, buf); RUNTIME_ASSERT(n > 0); RUNTIME_ASSERT(n <= 4); RUNTIME_ASSERT(n == utf8_first_byte_length_hint(data[0])); if (0 != memcmp(data, buf, n)) { printf("buf: %02x %02x %02x %02x\n", (unsigned char) buf[0], (unsigned char) buf[1], (unsigned char) buf[2], (unsigned char) buf[3]); printf("data: %02x %02x %02x %02x\n", (unsigned char) data[0], (unsigned char) data[1], (unsigned char) data[2], (unsigned char) data[3]); printf("d: U+%lx\n", (unsigned long) i); printf("i: %lu\n", (unsigned long) i); printf("n: %u\n", n); RUNTIME_ASSERT(0); } } } printf("valid=%u\n", valid); printf("PASSED\n"); }
static void handle_qhit(const char *data, size_t size) { const struct gnutella_qhit_header *header; const struct gnutella_guid *guid; const struct gnutella_qhit_item *item; size_t guid_offset = size - sizeof *guid; unsigned hits; size_t pos; RUNTIME_ASSERT(size <= GNUTELLA_MAX_PAYLOAD); if (size < sizeof *header) { fprintf(stderr, "handle_qhit(): Too little payload for header.\n"); return; } header = cast_to_const_void_ptr(data); hits = (unsigned char) header->hits; printf("Hits: %u\n", hits); printf("Address: %s\n", net_addr_port_to_string(net_addr_peek_ipv4(cast_to_const_char_ptr(header->addr)), peek_le16(header->port))); printf("Speed: %lu\n", (unsigned long) peek_le32(header->speed)); if (size < sizeof *header + sizeof *guid) { fprintf(stderr, "handle_qhit(): Insufficient payload for query hit.\n"); return; } if (size >= sizeof *header + sizeof *guid) { guid = cast_to_const_void_ptr(&data[guid_offset]); printf("Servent ID: %08lx-%08lx-%08lx-%08lx\n", (unsigned long) peek_be32(&guid->data[0]), (unsigned long) peek_be32(&guid->data[4]), (unsigned long) peek_be32(&guid->data[8]), (unsigned long) peek_be32(&guid->data[12])); } printf("----\n"); pos = sizeof *header; for (/* NOTHING */; hits > 0; hits--) { const char *nul_ptr; if (pos >= guid_offset || guid_offset - pos < sizeof *item + 2) break; item = cast_to_const_void_ptr(&data[pos]); printf("Index: %lu\n", (unsigned long) peek_le32(item->index)); printf("Size: %lu\n", (unsigned long) peek_le32(item->size)); pos += sizeof *item; nul_ptr = memchr(&data[pos], 0, guid_offset - pos); if (!nul_ptr) { fprintf(stderr, "handle_qhit(): Non-terminated filename.\n"); return; } else { size_t len; len = (nul_ptr - &data[pos]); if (len > (((size_t) -1) / 4 - 1)) { fprintf(stderr, "handle_qhit(): Filename is too long.\n"); /* Ignore */ } else { const char *p; size_t avail; printf("Filename: "); avail = len; p = &data[pos]; while (avail > 0) { uint32_t cp; cp = utf8_decode(p, avail); if ((uint32_t) -1 != cp) { uint8_t u_len, i; u_len = utf8_first_byte_length_hint((unsigned char) *p); RUNTIME_ASSERT(u_len > 0); RUNTIME_ASSERT(avail >= u_len); avail -= u_len; if (cp >= 0x20 && cp != 0x7f) { for (i = 0; i < u_len; i++) { putchar((unsigned char) p[i]); } } else { char ch = cp & 0xff; printf("%s", escape_buffer(&ch, 1)); } p += u_len; } else { if (verbosity > 0) { fprintf(stderr, "handle_qhit(): Invalid UTF-8.\n"); } break; } } } printf("\n"); pos += len; } RUNTIME_ASSERT(nul_ptr); RUNTIME_ASSERT(&data[pos] == nul_ptr); RUNTIME_ASSERT('\0' == *nul_ptr); pos++; RUNTIME_ASSERT(pos <= guid_offset); nul_ptr = memchr(&data[pos], 0, guid_offset - pos); if (!nul_ptr) { fprintf(stderr, "handle_qhit(): Non-terminated extension block.\n"); return; } else if (nul_ptr != &data[pos]) { size_t len = nul_ptr - &data[pos]; printf("Extension size: %lu\n", (unsigned long) len); handle_extension(&data[pos], len); pos += len; } RUNTIME_ASSERT(nul_ptr); RUNTIME_ASSERT(&data[pos] == nul_ptr); RUNTIME_ASSERT('\0' == *nul_ptr); pos++; RUNTIME_ASSERT(pos <= guid_offset); printf("------\n"); } if (hits > 0) { fprintf(stderr, "handle_qhit(): Expected %u more hits.\n", hits); } if (pos < guid_offset) { static const unsigned vendor_id_len = 4; printf("Extended QHD size: %lu\n", (unsigned long) guid_offset - pos); if (guid_offset - pos >= vendor_id_len) { printf("Vendor ID: %s\n", escape_buffer(&data[pos], vendor_id_len)); pos += vendor_id_len; if (pos < guid_offset) { uint8_t open_data_size = data[pos]; bool has_ggep = false; printf("Open data size: %u\n", open_data_size); pos++; if (open_data_size > guid_offset - pos) { printf("Open data size is too large.\n"); return; } if (open_data_size >= 2) { uint8_t mask = data[pos]; uint8_t value = data[pos + 1]; printf("mask: 0x%02x\n", mask); printf("value: 0x%02x\n", value); if (0x20 & mask) { has_ggep = 0x20 & value; printf("Has GGEP: %s\n", has_ggep ? "yes" : "no"); } if (0x10 & mask) { printf("Has speed: %s\n", (0x10 & value) ? "yes" : "no"); } if (0x08 & mask) { printf("Has uploaded: %s\n", (0x08 & value) ? "yes" : "no"); } if (0x04 & mask) { printf("Busy: %s\n", (0x04 & value) ? "yes" : "no"); } /* mask and value are swapped */ if (0x01 & value) { printf("Must push: %s\n", (0x01 & mask) ? "yes" : "no"); } } pos += open_data_size; if (pos < guid_offset) { size_t priv_data_size = guid_offset - pos; static const char id_deflate[] = "{deflate}"; const char *priv_data, *x; priv_data = &data[pos]; priv_data_size = guid_offset - pos; printf("Private data area size: %lu\n", (unsigned long) priv_data_size); handle_extension(priv_data, priv_data_size); x = compat_memmem(priv_data, priv_data_size, id_deflate, STATIC_STRLEN(id_deflate)); if (x) { char buf[64 * 1024]; const char *src; size_t n, src_len; src = &x[STATIC_STRLEN(id_deflate)]; src_len = priv_data_size - STATIC_STRLEN(id_deflate); n = buffer_inflate(buf, sizeof buf, src, src_len); if ((size_t) -1 != n) { printf("Inflated: %s\n", escape_buffer(buf, n)); } } pos += priv_data_size; } RUNTIME_ASSERT(pos == guid_offset); } } } printf("----\n"); }
static void html_render_text(struct render_context *ctx, const struct array text) { unsigned c_len; size_t i; bool whitespace = FALSE; struct array entity, current; entity = zero_array; current = zero_array; for (i = 0; i < text.size; i += c_len) { const unsigned char c = text.data[i]; bool is_whitespace; is_whitespace = FALSE; c_len = utf8_first_byte_length_hint(c); if (!ctx->preformatted && is_ascii_space(c)) { if (whitespace) continue; is_whitespace = TRUE; whitespace = TRUE; if (0x20 == c && i > 0 && i < text.size - c_len) { const unsigned char next_c = text.data[i + c_len]; if (!is_ascii_space(next_c)) is_whitespace = FALSE; } } else { whitespace = FALSE; } if ('&' == c || ';' == c || is_whitespace) { if (current.size > 0) { html_output_print(ctx->output, current); current = zero_array; } } if (is_whitespace) { if (i > 0 || ctx->closing) html_output_print(ctx->output, array_from_string(" ")); } else if ('&' == c) { if (entity.data) { html_render_entity(ctx, entity); } entity.data = deconstify_gchar(&text.data[i + c_len]); entity.size = 0; continue; } else if (';' == c) { if (entity.data) { html_render_entity(ctx, entity); entity = zero_array; continue; } } else if (entity.data) { entity.size += c_len; } else { if (!current.data) current.data = &text.data[i]; current.size += c_len; } } if (current.size > 0) { html_output_print(ctx->output, current); } }