I64 roundUp(I64 numToRound, I64 multiple) { if (multiple == 0) return numToRound; I64 remainder = Abs(numToRound) % multiple; if (remainder == 0) return numToRound; if (numToRound < 0) return -(Abs(numToRound) - remainder); else return numToRound + multiple - remainder; } #define WEB_RESPONSE_BUFFER_SIZE 1048576 * 4 U8 *web_page_buffer = CAlloc(WEB_RESPONSE_BUFFER_SIZE); U8 *web_resource_buffer = CAlloc(WEB_RESPONSE_BUFFER_SIZE); HttpUrl *web_current_url = NULL; /* clang-format off */ #include "TGL"; #include "Src/Doc"; #include "Src/Json"; #include "Src/MD5"; #include "Src/HTMLTokenizer"; #include "Src/HTMLRenderer"; /* clang-format on */ class WebPage { U8 sig[4]; @http_url *url; U8 title[STR_LEN]; CDoc *render_doc; JsonArray *animated_sprites; I64 num_of_animated_sprites; }; class WebSession { U8 sig[4]; JsonArray *history; I64 page_index; }; WebPage *@init_new_webpage() { WebPage *p = CAlloc(sizeof(WebPage)); MemCpy(&p->sig, "WebP", 4); // WebPage class signature p->render_doc = DocNew; DocMax(p->render_doc); p->animated_sprites = Json.CreateArray(); // Create array to store animated sprite data return p; } I64 Navigate(CDoc *doc, U8 *url_string) { if (!url_string) { PopUpOk("ERROR: URL string can not be empty."); return -1; } U8 buf[512]; WebPage *p = @init_new_webpage; StrPrint(buf, "web_current_url: 0x%08x\n", web_current_url); @vbox_debug_print(buf); p->url = @expand_url_from_string(url_string); StrPrint(buf, "new p->url is: 0x%08x\n", p->url); @vbox_debug_print(buf); if (!p->url) { PopUpOk(url_string); return 0; } // Store current parsed URL instance if (p->url) { web_current_url = p->url; StrPrint(buf, "Set web_current_url to: 0x%08x\n", p->url); @vbox_debug_print(buf); } CDoc *render_doc = p->render_doc; DocClear(render_doc); progress1 = 0; progress1_max = 1; StrPrint(progress1_desc, "Loading web page ..."); MemSet(web_page_buffer, NULL, WEB_RESPONSE_BUFFER_SIZE); @http_response *resp = @http_get(p->url, web_page_buffer); U8 *buffer = resp->body.data; I64 content_length = 0; I64 content_type = 0; I64 i; for (i = 0; i < resp->headers.count; i++) { if (!StrICmp(resp->headers.header[i]->key, "Content-Length")) { content_length = Str2I64(resp->headers.header[i]->value); // i = resp->headers.count; } if (!StrICmp(resp->headers.header[i]->key, "Content-Type")) { if (!MemCmp(resp->headers.header[i]->value, "text/html", 9)) content_type = 1; // i = resp->headers.count; } } if (content_type == 0) { // text/plain DocClear(render_doc); DocPrint(render_doc, "\dWW\d\dFG,8\d"); DocPutS(render_doc, buffer); goto navigate_finish; } I64 num_of_images = 0; StrPrint(progress1_desc, "Processing HTML data ..."); Node *node_tree = @html_tokenize_and_create_node_tree( buffer, WEB_RESPONSE_BUFFER_SIZE, &num_of_images); progress1_max = num_of_images; DocClear(render_doc); DocPrint(render_doc, "\dWW\d\dFG,8\d"); @render_node_tree(NULL, render_doc, node_tree); @calculate_indents_for_sprites(render_doc); navigate_finish: progress1_max = 0; DocTop(render_doc); DocClear(DocPut); DocInsDoc(DocPut, render_doc); DocTop(DocPut); // JsonItem *history_item = CAlloc(sizeof(JsonItem)); // history_item->value = p; // Json.AppendItem(s->history, p); // s->page_index++; return 0; } U0 @init_new_websession(CDoc *doc) { WebSession *s = CAlloc(sizeof(WebSession)); MemCpy(&s->sig, "WebS", 4); // WebSession class signature s->history = Json.CreateArray(); // Create array to store web page history s->page_index = -1; // Current page index in history array doc->user_data = s; // Assign WebSession class instance to specified CDoc } Bool @cmd_go_to_url(CTask *doc) { U8 *url_string = @popup_get_str("Web - World Wide Web browser for TempleOS", "Go to URL: "); if (url_string) { if (StrLen(url_string)) { Navigate(doc, url_string); return TRUE; } } return FALSE; } U0 @init_web_cache_folder() { U8 buf[512]; StrCpy(buf, "::/Tmp"); if (!FileFind(buf)) DirMk(buf); StrCpy(buf + StrLen(buf), "/Web"); if (!FileFind(buf)) DirMk(buf); StrCpy(buf + StrLen(buf), "/Cache"); if (!FileFind(buf)) DirMk(buf); } U0 Web() { web_current_url = NULL; U8 *res; @init_web_cache_folder; @task_doc_push('Web'); //@init_new_websession(DocPut); if (!@cmd_go_to_url(DocPut)) goto web_exit; while (1) { res = GetStr; if (!StrCmp(res, "")) goto web_exit; } web_exit: DocClear(DocPut); @task_doc_pop; }