tb_xml_node_ref_t tb_xml_reader_attributes(tb_xml_reader_ref_t reader) { // check tb_xml_reader_impl_t* impl = (tb_xml_reader_impl_t*)reader; tb_assert_and_check_return_val(impl && ( impl->event == TB_XML_READER_EVENT_DOCUMENT || impl->event == TB_XML_READER_EVENT_ELEMENT_BEG || impl->event == TB_XML_READER_EVENT_ELEMENT_END || impl->event == TB_XML_READER_EVENT_ELEMENT_EMPTY), tb_null); // init tb_char_t const* p = tb_string_cstr(&impl->element); tb_char_t const* e = p + tb_string_size(&impl->element); // skip name while (p < e && *p && !tb_isspace(*p)) p++; while (p < e && *p && tb_isspace(*p)) p++; // parse attributes tb_size_t n = 0; while (p < e) { // parse name tb_string_clear(&impl->attribute_name); for (; p < e && *p != '='; p++) if (!tb_isspace(*p)) tb_string_chrcat(&impl->attribute_name, *p); if (*p != '=') break; // parse data tb_string_clear(&impl->attribute_data); for (p++; p < e && (*p != '\'' && *p != '\"'); p++) ; if (*p != '\'' && *p != '\"') break; for (p++; p < e && (*p != '\'' && *p != '\"'); p++) tb_string_chrcat(&impl->attribute_data, *p); if (*p != '\'' && *p != '\"') break; p++; // append node if (tb_string_cstr(&impl->attribute_name) && tb_string_cstr(&impl->attribute_data)) { // node tb_xml_node_ref_t prev = n > 0? (tb_xml_node_ref_t)&impl->attributes[n - 1] : tb_null; tb_xml_node_ref_t node = (tb_xml_node_ref_t)&impl->attributes[n]; // init node tb_string_strcpy(&node->name, &impl->attribute_name); tb_string_strcpy(&node->data, &impl->attribute_data); // append node if (prev) prev->next = node; node->next = tb_null; // next n++; } } // ok? return n? (tb_xml_node_ref_t)&impl->attributes[0] : tb_null; }
tb_char_t const* tb_string_ltrim(tb_string_ref_t string) { // check tb_assert_and_check_return_val(string, tb_null); // init tb_char_t* s = (tb_char_t*)tb_string_cstr(string); tb_size_t n = tb_string_size(string); tb_check_return_val(s && n, tb_null); // done tb_char_t* p = s; tb_char_t* e = s + n; while (p < e && tb_isspace(*p)) p++; // strip it if (p < e) { // move it if exists spaces if (p > s) tb_buffer_memmov(string, p - s); } // clear it else tb_string_clear(string); // ok? return tb_string_cstr(string); }
static tb_object_ref_t tb_object_json_reader_done(tb_stream_ref_t stream) { // check tb_assert_and_check_return_val(stream, tb_null); // init reader tb_object_json_reader_t reader = {0}; reader.stream = stream; // skip spaces tb_char_t type = '\0'; while (tb_stream_left(stream)) { type = tb_stream_bread_s8(stream); if (!tb_isspace(type)) break; } // empty? tb_check_return_val(tb_stream_left(stream), tb_null); // the func tb_object_json_reader_func_t func = tb_object_json_reader_func(type); tb_assert_and_check_return_val(func, tb_null); // read it return func(&reader, type); }
tb_bool_t vm86_parser_get_offset_value(tb_char_t const** pp, tb_char_t const* e, tb_uint32_t* value, tb_hash_map_ref_t proc_labels, vm86_data_ref_t data) { // check tb_assert(pp && e && value && proc_labels); // done tb_bool_t ok = tb_false; tb_char_t const* p = *pp; do { // attempt to get segment name tb_char_t segment[16] = {0}; tb_bool_t has_segment = vm86_parser_get_segment_name(&p, e, segment, sizeof(segment)); // skip "short ..." if (p + 6 < e && !tb_strnicmp(p, "short ", 6)) p += 6; // skip the space while (p < e && tb_isspace(*p)) p++; // get instruction name tb_char_t name[256] = {0}; if (!vm86_parser_get_variable_name(&p, e, name, sizeof(name))) break; // is .data segment? if (has_segment && !tb_stricmp(segment, "ds")) *value = vm86_data_get(data, name, tb_null); // is .code segment? else if (has_segment && !tb_stricmp(segment, "cs")) *value = (tb_uint32_t)tb_hash_map_get(proc_labels, name); else { // get value if (tb_hash_map_find(proc_labels, name) != tb_iterator_tail(proc_labels)) *value = (tb_uint32_t)tb_hash_map_get(proc_labels, name); else if (vm86_data_is(data, name)) *value = vm86_data_get(data, name, tb_null); else break; } // check tb_assert(*value < TB_MAXU32); // trace tb_trace_d("offset: %s: %x", name, *value); // ok ok = tb_true; } while (0); // update the code pointer if ok if (ok) *pp = p; // ok? return ok; }
tb_bool_t vm86_parser_get_number_value(tb_char_t const** pp, tb_char_t const* e, tb_uint32_t* value) { // check tb_assert(pp && e && value); // done tb_bool_t ok = tb_false; tb_char_t const* p = *pp; do { // check tb_check_break(p < e && (tb_isdigit16(*p) || *p == '-')); // is sign? tb_bool_t is_sign = tb_false; if (*p == '-') { is_sign = tb_true; p++; } // save the base tb_char_t const* b = p; // skip the value while (p < e && tb_isdigit16(*p)) p++; // is hex? tb_bool_t is_hex = tb_false; if (p < e && *p == 'h') { is_hex = tb_true; p++; } // check end, exclude variable name tb_check_break(!tb_isalpha(*p) && *p != '_'); // save value *value = is_hex? tb_s16tou32(b) : tb_s10tou32(b); if (is_sign) *value = (tb_uint32_t)(((tb_sint32_t)*value) * -1); // skip the space while (p < e && tb_isspace(*p)) p++; // ok ok = tb_true; } while (0); // update the code pointer if ok if (ok) *pp = p; // ok? return ok; }
tb_bool_t vm86_parser_get_instruction_name(tb_char_t const** pp, tb_char_t const* e, tb_char_t* name, tb_size_t maxn) { // check tb_assert(pp && e && name && maxn); // done tb_bool_t ok = tb_false; tb_char_t const* p = *pp; do { // save base tb_char_t const* b = p; // skip name while (p < e && tb_isalpha(*p)) p++; tb_check_break(p <= e && p - b < maxn); // not instruction name? if (p < e && !tb_isspace(*p)) break; // save name tb_memcpy(name, b, p - b); // end name[p - b] = '\0'; // skip the space while (p < e && tb_isspace(*p)) p++; // ok ok = tb_true; } while (0); // update the code pointer if ok if (ok) *pp = p; // ok? return ok; }
static tb_void_t tb_check_is() { tb_int_t i = 0; for (i = 0; i < 256; i++) { if ((tb_isspace(i)? 1 : 0) != (isspace(i)? 1 : 0)) tb_printf("[e] isspace: 0x%02x\n", i); if ((tb_isalpha(i)? 1 : 0) != (isalpha(i)? 1 : 0)) tb_printf("[e] isalpha: 0x%02x\n", i); if ((tb_isdigit(i)? 1 : 0) != (isdigit(i)? 1 : 0)) tb_printf("[e] isdigit: 0x%02x\n", i); if ((tb_isupper(i)? 1 : 0) != (isupper(i)? 1 : 0)) tb_printf("[e] isupper: 0x%02x\n", i); if ((tb_islower(i)? 1 : 0) != (islower(i)? 1 : 0)) tb_printf("[e] islower: 0x%02x\n", i); if ((tb_isascii(i)? 1 : 0) != (isascii(i)? 1 : 0)) tb_printf("[e] isascii: 0x%02x\n", i); } }
static tb_bool_t tb_demo_spider_make_ourl(tb_demo_spider_t* spider, tb_char_t const* url, tb_char_t* data, tb_size_t maxn) { // check tb_assert_and_check_return_val(spider && url && data && maxn, tb_false); // skip protocol tb_char_t* p = (tb_char_t*)url; if (!tb_strnicmp(p, "http://", 7)) p += 7; else if (!tb_strnicmp(p, "https://", 8)) p += 8; // skip space while (*p && tb_isspace(*p)) p++; // format ourl tb_long_t n = tb_snprintf(data, maxn, "%s/%s", spider->root, p); tb_assert_and_check_return_val(n > 0 && n < maxn, tb_false); // no root? append '/' if (!tb_strchr(p, '/') && !tb_strchr(p, '\\')) data[n++] = '/'; tb_assert_and_check_return_val(n < maxn, tb_false); // '\\' => '/' if (data[n - 1] == '/') data[n - 1] = '/'; // directory? append index.html if (data[n - 1] == '/') n += tb_snprintf(data + n, maxn - n, "%s", "index.html"); tb_assert_and_check_return_val(n > 0 && n < maxn, tb_false); // end data[n] = '\0'; // replace '?' => '_' p = data; while (*p) { // replace if (*p == '?') *p = '_'; // next p++; } // trace tb_trace_d("make: %s => %s", url, data); // ok? return n > 0? tb_true : tb_false; }
static tb_object_ref_t tb_object_json_reader_func_array(tb_object_json_reader_t* reader, tb_char_t type) { // check tb_assert_and_check_return_val(reader && reader->stream && type == '[', tb_null); // init array tb_object_ref_t array = tb_object_array_init(TB_OBJECT_JSON_READER_ARRAY_GROW, tb_false); tb_assert_and_check_return_val(array, tb_null); // done tb_char_t ch; tb_bool_t ok = tb_true; while (ok && tb_stream_left(reader->stream)) { // read one character ch = tb_stream_bread_s8(reader->stream); // end? if (ch == ']') break; // no space? skip ',' else if (!tb_isspace(ch) && ch != ',') { // the func tb_object_json_reader_func_t func = tb_object_json_reader_func(ch); tb_assert_and_check_break_state(func, ok, tb_false); // read item tb_object_ref_t item = func(reader, ch); tb_assert_and_check_break_state(item, ok, tb_false); // append item tb_object_array_append(array, item); } } // failed? if (!ok) { // exit it if (array) tb_object_exit(array); array = tb_null; } // ok? return array; }
tb_uint64_t tb_s16tou64(tb_char_t const* s) { // check tb_assert_and_check_return_val(s, 0); // skip space while (tb_isspace(*s)) s++; // has sign? tb_int_t sign = 0; if (*s == '-') { sign = 1; s++; } // skip "0x" if (s[0] == '0' && (s[1] == 'x' || s[1] == 'X')) s += 2; // skip '0' while ((*s) == '0') s++; // compute number tb_uint64_t val = 0; while (*s) { tb_char_t ch = *s; if (tb_isdigit10(ch)) val = (val << 4) + (ch - '0'); else if (ch > ('a' - 1) && ch < ('f' + 1)) val = (val << 4) + (ch - 'a') + 10; else if (ch > ('A' - 1) && ch < ('F' + 1)) val = (val << 4) + (ch - 'A') + 10; else break; s++; } // is negative number? if (sign) val = ~val + 1; // the value return val; }
/* ////////////////////////////////////////////////////////////////////////////////////// * implementation */ tb_uint64_t tb_s2tou64(tb_char_t const* s) { // check tb_assert_and_check_return_val(s, 0); // skip space while (tb_isspace(*s)) s++; // has sign? tb_int_t sign = 0; if (*s == '-') { sign = 1; s++; } // skip "0b" if (s[0] == '0' && (s[1] == 'b' || s[1] == 'B')) s += 2; // skip '0' while ((*s) == '0') s++; // compute number tb_uint64_t val = 0; while (*s) { tb_char_t ch = *s; if (tb_isdigit2(ch)) val = (val << 1) + (ch - '0'); else break; s++; } // is negative number? if (sign) val = ~val + 1; // the value return val; }
tb_char_t const* tb_xml_reader_element(tb_xml_reader_ref_t reader) { // check tb_xml_reader_impl_t* impl = (tb_xml_reader_impl_t*)reader; tb_assert_and_check_return_val(impl && ( impl->event == TB_XML_READER_EVENT_ELEMENT_BEG || impl->event == TB_XML_READER_EVENT_ELEMENT_END || impl->event == TB_XML_READER_EVENT_ELEMENT_EMPTY), tb_null); // init tb_char_t const* p = tb_null; tb_char_t const* b = tb_string_cstr(&impl->element); tb_char_t const* e = b + tb_string_size(&impl->element); tb_assert_and_check_return_val(b, tb_null); // </name> or <name ... /> if (b < e && *b == '/') b++; for (p = b; p < e && *p && !tb_isspace(*p) && *p != '/'; p++) ; // ok? return p > b? tb_string_cstrncpy(&impl->element_name, b, p - b) : tb_null; }
static tb_void_t g2_svg_element_polygon_points(g2_svg_element_polygon_t* element, tb_char_t const* data) { // init tb_char_t const* p = data; tb_assert_and_check_return(p); // size tb_size_t size = 0; // trace tb_trace_impl("polygon: points"); while (*p) { if (!tb_isspace(*p) && tb_isdigit(*p)) p = g2_svg_element_polygon_point(element, p, &size); else p++; } // close path if (element->path) g2_path_close(element->path); }
tb_object_ref_t tb_object_dump(tb_object_ref_t object, tb_size_t format) { // check tb_assert_and_check_return_val(object, tb_null); // data tb_object_ref_t odata = tb_object_data(object, format); if (odata) { // the data and size tb_byte_t const* data = (tb_byte_t const*)tb_object_data_getp(odata); tb_size_t size = tb_object_data_size(odata); if (data && size) { // done tb_char_t const* p = (tb_char_t const*)data; tb_char_t const* e = (tb_char_t const*)data + size; tb_char_t b[4096 + 1]; if (p && p < e) { while (p < e && *p && tb_isspace(*p)) p++; while (p < e && *p) { tb_char_t* q = b; tb_char_t const* d = b + 4096; for (; p < e && q < d && *p; p++, q++) *q = *p; *q = '\0'; tb_printf("%s", b); } tb_printf("\n"); } } // exit data tb_object_exit(odata); } // the object return object; }
tb_object_ref_t tb_object_dump(tb_object_ref_t object) { // check tb_assert_and_check_return_val(object, tb_null); // data tb_object_ref_t odata = tb_object_data(object, TB_OBJECT_FORMAT_XML); if (odata) { // data & size tb_byte_t const* data = (tb_byte_t const*)tb_object_data_getp(odata); tb_size_t size = tb_object_data_size(odata); if (data && size) { tb_char_t const* p = tb_strstr((tb_char_t const*)data, "?>"); tb_char_t const* e = (tb_char_t const*)data + size; tb_char_t b[4096 + 1]; if (p && p + 2 < e) { p += 2; while (p < e && *p && tb_isspace(*p)) p++; while (p < e && *p) { tb_char_t* q = b; tb_char_t const* d = b + 4096; for (; p < e && q < d && *p; p++, q++) *q = *p; *q = '\0'; tb_printf("%s", b); } tb_printf("\n"); } } // exit data tb_object_exit(odata); } return object; }
tb_char_t const* tb_string_rtrim(tb_string_ref_t string) { // check tb_assert_and_check_return_val(string, tb_null); // init tb_char_t* s = (tb_char_t*)tb_string_cstr(string); tb_size_t n = tb_string_size(string); tb_check_return_val(s && n, tb_null); // done tb_char_t* e = s + n - 1; while (e >= s && tb_isspace(*e)) e--; // strip it if (e >= s) tb_string_strip(string, e - s + 1); // clear it else tb_string_clear(string); // ok? return tb_string_cstr(string); }
/* ////////////////////////////////////////////////////////////////////////////////////// * implementation */ tb_bool_t vm86_parser_get_variable_name(tb_char_t const** pp, tb_char_t const* e, tb_char_t* name, tb_size_t maxn) { // check tb_assert(pp && e && name && maxn); // done tb_bool_t ok = tb_false; tb_char_t const* p = *pp; do { // save base tb_char_t const* b = p; // check tb_check_break(p < e && (tb_isalpha(*p) || *p == '_')); p++; // get name while (p < e && (tb_isalpha(*p) || *p == '_' || tb_isdigit(*p))) p++; tb_check_break(p <= e && p - b < maxn); tb_memcpy(name, b, p - b); // end name[p - b] = '\0'; // skip the space while (p < e && tb_isspace(*p)) p++; // ok ok = tb_true; } while (0); // update the code pointer if ok if (ok) *pp = p; // ok? return ok; }
tb_double_t tb_stod(tb_char_t const* s) { // check tb_assert_and_check_return_val(s, 0); // skip space tb_char_t const* p = s; while (tb_isspace(*p)) p++; // has sign? if (*p == '-') p++; // is hex? if (*p++ == '0') { if (*p == 'x' || *p == 'X') return tb_s16tod(s); else if (*p == 'b' || *p == 'B') return tb_s2tod(s); else return tb_s8tod(s); } else return tb_s10tod(s); }
tb_uint64_t tb_s10tou64(tb_char_t const* s) { // check tb_assert_and_check_return_val(s, 0); // skip space while (tb_isspace(*s)) s++; // has sign? tb_int_t sign = 0; if (*s == '-') { sign = 1; s++; } // skip '0' while ((*s) == '0') s++; // compute number tb_uint64_t val = 0; while (*s) { tb_char_t ch = *s; if (tb_isdigit10(ch)) val = val * 10 + (ch - '0'); else break; s++; } // is negative number? if (sign) val = ~val + 1; // the value return val; }
static tb_object_ref_t tb_object_json_reader_func_dictionary(tb_object_json_reader_t* reader, tb_char_t type) { // check tb_assert_and_check_return_val(reader && reader->stream && type == '{', tb_null); // init key name tb_static_string_t kname; tb_char_t kdata[8192]; if (!tb_static_string_init(&kname, kdata, 8192)) return tb_null; // init dictionary tb_object_ref_t dictionary = tb_object_dictionary_init(0, tb_false); tb_assert_and_check_return_val(dictionary, tb_null); // walk tb_char_t ch; tb_bool_t ok = tb_true; tb_bool_t bkey = tb_false; tb_size_t bstr = 0; while (ok && tb_stream_left(reader->stream)) { // read one character ch = tb_stream_bread_s8(reader->stream); // end? if (ch == '}') break; // no space? skip ',' else if (!tb_isspace(ch) && ch != ',') { // no key? if (!bkey) { // is str? if (ch == '\"' || ch == '\'') bstr = !bstr; // is key end? else if (!bstr && ch == ':') bkey = tb_true; // append key else if (bstr) tb_static_string_chrcat(&kname, ch); } // key ok? read val else { // trace tb_trace_d("key: %s", tb_static_string_cstr(&kname)); // the func tb_object_json_reader_func_t func = tb_object_json_reader_func(ch); tb_assert_and_check_break_state(func, ok, tb_false); // read val tb_object_ref_t val = func(reader, ch); tb_assert_and_check_break_state(val, ok, tb_false); // set key => val tb_object_dictionary_insert(dictionary, tb_static_string_cstr(&kname), val); // reset key bstr = 0; bkey = tb_false; tb_static_string_clear(&kname); } } } // failed? if (!ok) { // exit it if (dictionary) tb_object_exit(dictionary); dictionary = tb_null; } // exit key name tb_static_string_exit(&kname); // ok? return dictionary; }
tb_double_t tb_s16tod(tb_char_t const* s) { // check tb_assert_and_check_return_val(s, 0); // skip space while (tb_isspace(*s)) s++; // has sign? tb_int_t sign = 0; if (*s == '-') { sign = 1; s++; } // nan? if (s[0] == 'n' && s[1] == 'a' && s[2] == 'n') return TB_NAN; // inf or -inf? if (s[0] == 'i' && s[1] == 'n' && s[2] == 'f') return sign? -TB_INF : TB_INF; // skip "0x" if (s[0] == '0' && (s[1] == 'x' || s[1] == 'X')) s += 2; // compute double: lhs.rhs tb_int_t dec = 0; tb_uint64_t lhs = 0; tb_double_t rhs = 0.; tb_int_t zeros = 0; tb_int8_t decimals[256]; tb_int8_t* d = decimals; tb_int8_t* e = decimals + 256; while (*s) { tb_char_t ch = *s; // is the part of decimal? if (ch == '.') { if (!dec) { dec = 1; s++; continue ; } else break; } // parse integer & decimal if (tb_isdigit10(ch)) { // save decimals if (dec) { if (d < e) { if (ch != '0') { // fill '0' while (zeros--) *d++ = 0; zeros = 0; // save decimal *d++ = ch - '0'; } else zeros++; } } else lhs = (lhs << 4) + (ch - '0'); } else if (ch > ('a' - 1) && ch < ('f' + 1)) { // save decimals if (dec) { if (d < e) { if (ch != '0') { // fill '0' while (zeros--) *d++ = 0; zeros = 0; // save decimal *d++ = (ch - 'a') + 10; } else zeros++; } } else lhs = (lhs << 4) + (ch - 'a') + 10; } else if (ch > ('A' - 1) && ch < ('F' + 1)) { // save decimals if (dec) { if (d < e) { if (ch != '0') { // fill '0' while (zeros--) *d++ = 0; zeros = 0; // save decimal *d++ = (ch - 'A') + 10; } else zeros++; } } else lhs = (lhs << 4) + (ch - 'A') + 10; } else break; s++; } // check tb_assert_and_check_return_val(d <= decimals + 256, 0); // compute decimal while (d-- > decimals) rhs = (rhs + *d) / 16; // merge return (sign? ((tb_double_t)lhs + rhs) * -1. : ((tb_double_t)lhs + rhs)); }
/* ////////////////////////////////////////////////////////////////////////////////////// * main */ tb_int_t tb_demo_stream_async_stream_main(tb_int_t argc, tb_char_t** argv) { // done tb_demo_context_t context = {0}; do { // init option context.option = tb_option_init("astream", "the astream demo", g_options); tb_assert_and_check_break(context.option); // done option if (tb_option_done(context.option, argc - 1, &argv[1])) { // debug and verbose context.debug = tb_option_find(context.option, "debug")? tb_false : tb_true; context.verbose = tb_option_find(context.option, "no-verbose")? tb_false : tb_true; // done url if (tb_option_find(context.option, "url")) { // init event context.event = tb_event_init(); tb_assert_and_check_break(context.event); // init istream context.istream = tb_async_stream_init_from_url(tb_null, tb_option_item_cstr(context.option, "url")); tb_assert_and_check_break(context.istream); // ctrl http if (tb_async_stream_type(context.istream) == TB_STREAM_TYPE_HTTP) { // enable gzip? if (tb_option_find(context.option, "gzip")) { // auto unzip if (!tb_async_stream_ctrl(context.istream, TB_STREAM_CTRL_HTTP_SET_AUTO_UNZIP, 1)) break; // need gzip if (!tb_async_stream_ctrl(context.istream, TB_STREAM_CTRL_HTTP_SET_HEAD, "Accept-Encoding", "gzip,deflate")) break; } // enable debug? if (!tb_async_stream_ctrl(context.istream, TB_STREAM_CTRL_HTTP_SET_HEAD_FUNC, context.debug? tb_demo_istream_head_func : tb_null)) break; // custem header? if (tb_option_find(context.option, "header")) { // init tb_string_t key; tb_string_t val; tb_string_init(&key); tb_string_init(&val); // done tb_bool_t k = tb_true; tb_char_t const* p = tb_option_item_cstr(context.option, "header"); while (*p) { // is key? if (k) { if (*p != ':' && !tb_isspace(*p)) tb_string_chrcat(&key, *p++); else if (*p == ':') { // skip ':' p++; // skip space while (*p && tb_isspace(*p)) p++; // is val now k = tb_false; } else p++; } // is val? else { if (*p != ';') tb_string_chrcat(&val, *p++); else { // skip ';' p++; // skip space while (*p && tb_isspace(*p)) p++; // set header if (tb_string_size(&key) && tb_string_size(&val)) { if (context.debug) tb_printf("header: %s: %s\n", tb_string_cstr(&key), tb_string_cstr(&val)); if (!tb_async_stream_ctrl(context.istream, TB_STREAM_CTRL_HTTP_SET_HEAD, tb_string_cstr(&key), tb_string_cstr(&val))) break; } // is key now k = tb_true; // clear key & val tb_string_clear(&key); tb_string_clear(&val); } } } // set header if (tb_string_size(&key) && tb_string_size(&val)) { if (context.debug) tb_printf("header: %s: %s\n", tb_string_cstr(&key), tb_string_cstr(&val)); if (!tb_async_stream_ctrl(context.istream, TB_STREAM_CTRL_HTTP_SET_HEAD, tb_string_cstr(&key), tb_string_cstr(&val))) break; } // exit tb_string_exit(&key); tb_string_exit(&val); } // keep alive? if (tb_option_find(context.option, "keep-alive")) { if (!tb_async_stream_ctrl(context.istream, TB_STREAM_CTRL_HTTP_SET_HEAD, "Connection", "keep-alive")) break; } // post-data? if (tb_option_find(context.option, "post-data")) { tb_char_t const* post_data = tb_option_item_cstr(context.option, "post-data"); tb_hize_t post_size = tb_strlen(post_data); if (!tb_async_stream_ctrl(context.istream, TB_STREAM_CTRL_HTTP_SET_METHOD, TB_HTTP_METHOD_POST)) break; if (!tb_async_stream_ctrl(context.istream, TB_STREAM_CTRL_HTTP_SET_POST_DATA, post_data, post_size)) break; if (!tb_async_stream_ctrl(context.istream, TB_STREAM_CTRL_HTTP_SET_POST_FUNC, tb_demo_http_post_func)) break; if (context.debug) tb_printf("post: %llu\n", post_size); } // post-file? else if (tb_option_find(context.option, "post-file")) { tb_char_t const* url = tb_option_item_cstr(context.option, "post-file"); if (!tb_async_stream_ctrl(context.istream, TB_STREAM_CTRL_HTTP_SET_METHOD, TB_HTTP_METHOD_POST)) break; if (!tb_async_stream_ctrl(context.istream, TB_STREAM_CTRL_HTTP_SET_POST_URL, url)) break; if (!tb_async_stream_ctrl(context.istream, TB_STREAM_CTRL_HTTP_SET_POST_FUNC, tb_demo_http_post_func)) break; if (context.debug) tb_printf("post: %s\n", url); } } // set range if (tb_option_find(context.option, "range")) { tb_char_t const* p = tb_option_item_cstr(context.option, "range"); if (p) { // the bof tb_hize_t eof = 0; tb_hize_t bof = tb_atoll(p); while (*p && tb_isdigit(*p)) p++; if (*p == '-') { p++; eof = tb_atoll(p); } if (!tb_async_stream_ctrl(context.istream, TB_STREAM_CTRL_HTTP_SET_RANGE, bof, eof)) break; } } // set timeout if (tb_option_find(context.option, "timeout")) { tb_size_t timeout = tb_option_item_uint32(context.option, "timeout"); tb_async_stream_ctrl(context.istream, TB_STREAM_CTRL_SET_TIMEOUT, &timeout); } // print verbose info if (context.verbose) tb_printf("open: %s: ..\n", tb_option_item_cstr(context.option, "url")); // open istream if (!tb_async_stream_open(context.istream, tb_demo_istream_open_func, &context)) { // print verbose info if (context.verbose) tb_printf("open: failed\n"); break; } // wait it tb_event_wait(context.event, -1); } else tb_option_help(context.option); } else tb_option_help(context.option); } while (0); // exit transfer if (context.transfer) tb_async_transfer_exit(context.transfer); context.transfer = tb_null; // exit istream if (context.istream) tb_async_stream_exit(context.istream); context.istream = tb_null; // exit ostream if (context.ostream) tb_async_stream_exit(context.ostream); context.ostream = tb_null; // exit option if (context.option) tb_option_exit(context.option); context.option = tb_null; // exit event if (context.event) tb_event_exit(context.event); context.event = tb_null; return 0; }
static tb_object_ref_t tb_object_xplist_reader_func_data(tb_object_xplist_reader_t* reader, tb_size_t event) { // check tb_assert_and_check_return_val(reader && reader->reader && event, tb_null); // empty? if (event == TB_XML_READER_EVENT_ELEMENT_EMPTY) return tb_object_data_init_from_data(tb_null, 0); // done tb_bool_t leave = tb_false; tb_char_t* base64 = tb_null; tb_object_ref_t data = tb_null; while (!leave && (event = tb_xml_reader_next(reader->reader))) { switch (event) { case TB_XML_READER_EVENT_ELEMENT_END: { // name tb_char_t const* name = tb_xml_reader_element(reader->reader); tb_assert_and_check_break_state(name, leave, tb_true); // is end? if (!tb_stricmp(name, "data")) { // empty? if (!data) data = tb_object_data_init_from_data(tb_null, 0); // leave it leave = tb_true; } } break; case TB_XML_READER_EVENT_TEXT: { // text tb_char_t const* text = tb_xml_reader_text(reader->reader); tb_assert_and_check_break_state(text, leave, tb_true); tb_trace_d("data: %s", text); // base64 base64 = tb_strdup(text); tb_char_t* p = base64; tb_char_t* q = p; for (; *p; p++) if (!tb_isspace(*p)) *q++ = *p; *q = '\0'; // decode base64 data tb_char_t const* ib = base64; tb_size_t in = tb_strlen(base64); if (in) { tb_size_t on = in; tb_byte_t* ob = tb_malloc0_bytes(on); tb_assert_and_check_break_state(ob && on, leave, tb_true); on = tb_base64_decode(ib, in, ob, on); tb_trace_d("base64: %u => %u", in, on); // init data data = tb_object_data_init_from_data(ob, on); tb_free(ob); } else data = tb_object_data_init_from_data(tb_null, 0); tb_assert_and_check_break_state(data, leave, tb_true); } break; default: break; } } // free if (base64) tb_free(base64); // ok? return data; }
/* ////////////////////////////////////////////////////////////////////////////////////// * implementation */ tb_time_t tb_http_date_from_cstr(tb_char_t const* cstr, tb_size_t size) { // check tb_assert_and_check_return_val(cstr && size, 0); // done tb_tm_t tm = {0}; tb_time_t date = 0; tb_char_t const* p = cstr; tb_char_t const* e = cstr + size; do { // skip space while (p < e && tb_isspace(*p)) p++; // ignore #if 0 // parse week if ((p + 6 < e && !tb_strnicmp(p, "Monday", 6)) || (p + 3 < e && !tb_strnicmp(p, "Mon", 3))) tm.week = 1; else if ((p + 7 < e && !tb_strnicmp(p, "Tuesday", 7)) || (p + 3 < e && !tb_strnicmp(p, "Tue", 3))) tm.week = 2; else if ((p + 9 < e && !tb_strnicmp(p, "Wednesday", 9)) || (p + 3 < e && !tb_strnicmp(p, "Wed", 3))) tm.week = 3; else if ((p + 8 < e && !tb_strnicmp(p, "Thursday", 8)) || (p + 3 < e && !tb_strnicmp(p, "Thu", 3))) tm.week = 4; else if ((p + 6 < e && !tb_strnicmp(p, "Friday", 6)) || (p + 3 < e && !tb_strnicmp(p, "Fri", 3))) tm.week = 5; else if ((p + 8 < e && !tb_strnicmp(p, "Saturday", 8)) || (p + 3 < e && !tb_strnicmp(p, "Sat", 3))) tm.week = 6; else if ((p + 6 < e && !tb_strnicmp(p, "Sunday", 6)) || (p + 3 < e && !tb_strnicmp(p, "Sun", 3))) tm.week = 7; #endif // skip week while (p < e && *p != ',' && !tb_isspace(*p)) p++; if (p < e && (*p == ',' || tb_isspace(*p))) p++; // skip space while (p < e && tb_isspace(*p)) p++; // is day? tb_bool_t year_suffix = tb_true; if (p < e && tb_isdigit(*p)) { /* prefix year * * .e.g * year_suffix == false: Sun, 06-Nov-1994 08:49:37 * year_suffix == true: Sun Nov 6 08:49:37 1994 */ year_suffix = tb_false; // parse day tm.mday = tb_s10tou32(p); // skip day while (p < e && *p != '-' && !tb_isspace(*p)) p++; if (p < e && (*p == '-' || tb_isspace(*p))) p++; } // parse month if (p + 3 < e && !tb_strnicmp(p, "Jan", 3)) tm.month = 1; else if (p + 3 < e && !tb_strnicmp(p, "Feb", 3)) tm.month = 2; else if (p + 3 < e && !tb_strnicmp(p, "Mar", 3)) tm.month = 3; else if (p + 3 < e && !tb_strnicmp(p, "Apr", 3)) tm.month = 4; else if (p + 3 < e && !tb_strnicmp(p, "May", 3)) tm.month = 5; else if (p + 3 < e && !tb_strnicmp(p, "Jun", 3)) tm.month = 6; else if (p + 3 < e && !tb_strnicmp(p, "Jul", 3)) tm.month = 7; else if (p + 3 < e && !tb_strnicmp(p, "Aug", 3)) tm.month = 8; else if (p + 3 < e && !tb_strnicmp(p, "Sep", 3)) tm.month = 9; else if (p + 3 < e && !tb_strnicmp(p, "Oct", 3)) tm.month = 10; else if (p + 3 < e && !tb_strnicmp(p, "Nov", 3)) tm.month = 11; else if (p + 3 < e && !tb_strnicmp(p, "Dec", 3)) tm.month = 12; // skip month while (p < e && *p != '-' && !tb_isspace(*p)) p++; if (p < e && (*p == '-' || tb_isspace(*p))) p++; // year suffix? if (year_suffix) { // parse day tm.mday = tb_s10tou32(p); } else { // parse year tm.year = tb_s10tou32(p); if (tm.year < 100) tm.year += 2000; } // skip year or day while (p < e && !tb_isspace(*p)) p++; while (p < e && tb_isspace(*p)) p++; // parse hour tm.hour = tb_s10tou32(p); // skip hour while (p < e && *p != ':') p++; if (p < e && *p == ':') p++; // parse minute tm.minute = tb_s10tou32(p); // skip minute while (p < e && *p != ':') p++; if (p < e && *p == ':') p++; // parse second tm.second = tb_s10tou32(p); // year suffix? if (year_suffix) { // skip time while (p < e && !tb_isspace(*p)) p++; while (p < e && tb_isspace(*p)) p++; // parse year tm.year = tb_s10tou32(p); if (tm.year < 100) tm.year += 1900; } // make date date = tb_gmmktime(&tm); } while (0); // ok? return date; }
tb_bool_t vm86_parser_get_register(tb_char_t const** pp, tb_char_t const* e, tb_uint16_t* r) { // check tb_assert(pp && e && r); // done tb_bool_t ok = tb_false; tb_char_t const* p = *pp; do { // save base tb_char_t const* b = p; // get instruction name tb_char_t name[64] = {0}; while (p < e && tb_isalpha(*p)) p++; tb_check_break(p <= e && p - b < sizeof(name)); tb_memcpy(name, b, p - b); // skip the space while (p < e && tb_isspace(*p)) p++; // the register entry type typedef struct __vm86_register_entry_t { // the register name tb_char_t const* name; // the register index tb_uint8_t index; }vm86_register_entry_t, *vm86_register_entry_ref_t; // the registers static vm86_register_entry_t s_registers[] = { { "ah", VM86_REGISTER_EAX | VM86_REGISTER_AH } , { "al", VM86_REGISTER_EAX | VM86_REGISTER_AL } , { "ax", VM86_REGISTER_EAX | VM86_REGISTER_AX } , { "bh", VM86_REGISTER_EBX | VM86_REGISTER_BH } , { "bl", VM86_REGISTER_EBX | VM86_REGISTER_BL } , { "bx", VM86_REGISTER_EBX | VM86_REGISTER_BX } , { "ch", VM86_REGISTER_ECX | VM86_REGISTER_CH } , { "cl", VM86_REGISTER_ECX | VM86_REGISTER_CL } , { "cx", VM86_REGISTER_ECX | VM86_REGISTER_CX } , { "dh", VM86_REGISTER_EDX | VM86_REGISTER_DH } , { "dl", VM86_REGISTER_EDX | VM86_REGISTER_DL } , { "dx", VM86_REGISTER_EDX | VM86_REGISTER_DX } , { "eax", VM86_REGISTER_EAX } , { "ebp", VM86_REGISTER_EBP } , { "ebx", VM86_REGISTER_EBX } , { "ecx", VM86_REGISTER_ECX } , { "edi", VM86_REGISTER_EDI } , { "edx", VM86_REGISTER_EDX } , { "esi", VM86_REGISTER_ESI } , { "esp", VM86_REGISTER_ESP } }; // init iterator tb_array_iterator_t array_iterator; tb_iterator_ref_t iterator = tb_array_iterator_init_mem(&array_iterator, s_registers, tb_arrayn(s_registers), sizeof(vm86_register_entry_t)); // find register by the binary search tb_size_t itor = tb_binary_find_all_if(iterator, vm86_parser_comp_register, name); tb_check_break(itor != tb_iterator_tail(iterator)); // get the register vm86_register_entry_ref_t entry = (vm86_register_entry_ref_t)tb_iterator_item(iterator, itor); tb_assert_and_check_break(entry && (entry->index & VM86_REGISTER_MASK) < VM86_REGISTER_MAXN); // save register *r = entry->index; // trace tb_trace_d("register: %s: %x", name, entry->index); // ok ok = tb_true; } while (0); // update the code pointer if ok if (ok) *pp = p; // ok? return ok; }
static tb_void_t tb_demo_http_session_head_parse(tb_demo_http_session_ref_t session) { // check tb_assert_and_check_return(session); // the first line? tb_char_t const* p = session->line; if (!session->line_index) { // parse get if (!tb_strnicmp(p, "GET", 3)) { session->code = TB_HTTP_CODE_OK; session->method = TB_HTTP_METHOD_GET; p += 3; } // parse post else if (!tb_strnicmp(p, "POST", 4)) { session->code = TB_HTTP_CODE_NOT_IMPLEMENTED; session->method = TB_HTTP_METHOD_POST; p += 4; } // other method is not implemented else session->code = TB_HTTP_CODE_NOT_IMPLEMENTED; // get or post? parse the path if ( session->method == TB_HTTP_METHOD_GET || session->method == TB_HTTP_METHOD_POST) { // skip space while (*p && tb_isspace(*p)) p++; // append path tb_size_t i = 0; while (*p && !tb_isspace(*p) && i < sizeof(session->path) - 1) session->path[i++] = *p++; session->path[i] = '\0'; } } // key: value? else { // seek to value while (*p && *p != ':') p++; tb_assert_and_check_return(*p); p++; while (*p && tb_isspace(*p)) p++; // no value tb_check_return(*p); // parse content-length if (!tb_strnicmp(session->line, "Content-Length", 14)) session->content_size = tb_stou64(p); // parse connection else if (!tb_strnicmp(session->line, "Connection", 10)) session->keep_alive = !tb_stricmp(p, "keep-alive"); // parse range else if (!tb_strnicmp(session->line, "Range", 5)) session->code = TB_HTTP_CODE_NOT_IMPLEMENTED; } }
/* ////////////////////////////////////////////////////////////////////////////////////// * main */ tb_int_t tb_demo_stream_main(tb_int_t argc, tb_char_t** argv) { // done tb_option_ref_t option = tb_null; tb_stream_ref_t istream = tb_null; tb_stream_ref_t ostream = tb_null; tb_stream_ref_t pstream = tb_null; do { // init option option = tb_option_init("stream", "the stream demo", g_options); tb_assert_and_check_break(option); // done option if (tb_option_done(option, argc - 1, &argv[1])) { // debug & verbose tb_bool_t debug = tb_option_find(option, "debug"); tb_bool_t verbose = tb_option_find(option, "no-verbose")? tb_false : tb_true; // done url if (tb_option_find(option, "url")) { // init istream istream = tb_stream_init_from_url(tb_option_item_cstr(option, "url")); tb_assert_and_check_break(istream); // ctrl http if (tb_stream_type(istream) == TB_STREAM_TYPE_HTTP) { // enable gzip? if (tb_option_find(option, "gzip")) { // auto unzip if (!tb_stream_ctrl(istream, TB_STREAM_CTRL_HTTP_SET_AUTO_UNZIP, 1)) break; // need gzip if (!tb_stream_ctrl(istream, TB_STREAM_CTRL_HTTP_SET_HEAD, "Accept-Encoding", "gzip,deflate")) break; } // enable debug? if (!tb_stream_ctrl(istream, TB_STREAM_CTRL_HTTP_SET_HEAD_FUNC, debug? tb_demo_stream_head_func : tb_null)) break; // custem header? if (tb_option_find(option, "header")) { // init tb_string_t key; tb_string_t val; tb_string_init(&key); tb_string_init(&val); // done tb_bool_t k = tb_true; tb_char_t const* p = tb_option_item_cstr(option, "header"); while (*p) { // is key? if (k) { if (*p != ':' && !tb_isspace(*p)) tb_string_chrcat(&key, *p++); else if (*p == ':') { // skip ':' p++; // skip space while (*p && tb_isspace(*p)) p++; // is val now k = tb_false; } else p++; } // is val? else { if (*p != ';') tb_string_chrcat(&val, *p++); else { // skip ';' p++; // skip space while (*p && tb_isspace(*p)) p++; // set header if (tb_string_size(&key) && tb_string_size(&val)) { if (debug) tb_printf("header: %s: %s\n", tb_string_cstr(&key), tb_string_cstr(&val)); if (!tb_stream_ctrl(istream, TB_STREAM_CTRL_HTTP_SET_HEAD, tb_string_cstr(&key), tb_string_cstr(&val))) break; } // is key now k = tb_true; // clear key & val tb_string_clear(&key); tb_string_clear(&val); } } } // set header if (tb_string_size(&key) && tb_string_size(&val)) { if (debug) tb_printf("header: %s: %s\n", tb_string_cstr(&key), tb_string_cstr(&val)); if (!tb_stream_ctrl(istream, TB_STREAM_CTRL_HTTP_SET_HEAD, tb_string_cstr(&key), tb_string_cstr(&val))) break; } // exit tb_string_exit(&key); tb_string_exit(&val); } // keep alive? if (tb_option_find(option, "keep-alive")) { if (!tb_stream_ctrl(istream, TB_STREAM_CTRL_HTTP_SET_HEAD, "Connection", "keep-alive")) break; } // post-data? if (tb_option_find(option, "post-data")) { tb_char_t const* post_data = tb_option_item_cstr(option, "post-data"); tb_hize_t post_size = tb_strlen(post_data); if (!tb_stream_ctrl(istream, TB_STREAM_CTRL_HTTP_SET_METHOD, TB_HTTP_METHOD_POST)) break; if (!tb_stream_ctrl(istream, TB_STREAM_CTRL_HTTP_SET_POST_DATA, post_data, post_size)) break; if (!tb_stream_ctrl(istream, TB_STREAM_CTRL_HTTP_SET_POST_FUNC, tb_demo_http_post_func)) break; if (debug) tb_printf("post: %llu\n", post_size); } // post-file? else if (tb_option_find(option, "post-file")) { tb_char_t const* url = tb_option_item_cstr(option, "post-file"); if (!tb_stream_ctrl(istream, TB_STREAM_CTRL_HTTP_SET_METHOD, TB_HTTP_METHOD_POST)) break; if (!tb_stream_ctrl(istream, TB_STREAM_CTRL_HTTP_SET_POST_URL, url)) break; if (!tb_stream_ctrl(istream, TB_STREAM_CTRL_HTTP_SET_POST_FUNC, tb_demo_http_post_func)) break; if (debug) tb_printf("post: %s\n", url); } } // set range if (tb_option_find(option, "range")) { tb_char_t const* p = tb_option_item_cstr(option, "range"); if (p) { // the bof tb_hize_t eof = 0; tb_hize_t bof = tb_atoll(p); while (*p && tb_isdigit(*p)) p++; if (*p == '-') { p++; eof = tb_atoll(p); } if (!tb_stream_ctrl(istream, TB_STREAM_CTRL_HTTP_SET_RANGE, bof, eof)) break; } } // set timeout if (tb_option_find(option, "timeout")) { tb_size_t timeout = tb_option_item_uint32(option, "timeout"); if (!tb_stream_ctrl(istream, TB_STREAM_CTRL_SET_TIMEOUT, timeout)) break; } // print verbose info if (verbose) tb_printf("open: %s: ..\n", tb_option_item_cstr(option, "url")); // open istream if (!tb_stream_open(istream)) { // print verbose info if (verbose) tb_printf("open: %s\n", tb_state_cstr(tb_stream_state(istream))); break; } // print verbose info if (verbose) tb_printf("open: ok\n"); // init ostream if (tb_option_find(option, "more0")) { // the path tb_char_t const* path = tb_option_item_cstr(option, "more0"); // init ostream = tb_stream_init_from_file(path, TB_FILE_MODE_RW | TB_FILE_MODE_CREAT | TB_FILE_MODE_BINARY | TB_FILE_MODE_TRUNC); // print verbose info if (verbose) tb_printf("save: %s\n", path); } else { // the name tb_char_t const* name = tb_strrchr(tb_option_item_cstr(option, "url"), '/'); if (!name) name = tb_strrchr(tb_option_item_cstr(option, "url"), '\\'); if (!name) name = "/stream.file"; // the path tb_char_t path[TB_PATH_MAXN] = {0}; if (tb_directory_current(path, TB_PATH_MAXN)) tb_strcat(path, name); else break; // init file ostream = tb_stream_init_from_file(path, TB_FILE_MODE_RW | TB_FILE_MODE_CREAT | TB_FILE_MODE_BINARY | TB_FILE_MODE_TRUNC); // print verbose info if (verbose) tb_printf("save: %s\n", path); } tb_assert_and_check_break(ostream); // the limit rate tb_size_t limitrate = 0; if (tb_option_find(option, "limitrate")) limitrate = tb_option_item_uint32(option, "limitrate"); // save it tb_hong_t save = 0; tb_demo_context_t context = {0}; context.verbose = verbose; if ((save = tb_transfer_done(istream, ostream, limitrate, tb_demo_stream_save_func, &context)) < 0) break; } else tb_option_help(option); } else tb_option_help(option); } while (0); // exit pstream if (pstream) tb_stream_exit(pstream); pstream = tb_null; // exit istream if (istream) tb_stream_exit(istream); istream = tb_null; // exit ostream if (ostream) tb_stream_exit(ostream); ostream = tb_null; // exit option if (option) tb_option_exit(option); option = tb_null; return 0; }