Files
TOSWeb/Web.HC
T
2022-05-27 13:17:24 -04:00

196 lines
4.4 KiB
HolyC

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);
/* clang-format off */
#include "TGL";
#include "Src/Debug";
#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;
}
if (!doc->user_data) {
PopUpOk("ERROR: WebSession is not initialized for current document.");
return -1;
}
WebSession *s = doc->user_data;
if (MemCmp(s->sig, "WebS", 4)) {
PopUpOk("ERROR: Corrupt WebSession data (failed signature check).");
return -1;
}
WebPage *p = @init_new_webpage;
p->url = @http_parse_url(url_string);
U8 buf[512];
if (!StrCmp(p->url->scheme, "//")) {
StrCpy(buf, "https:");
StrCpy(buf + StrLen(buf), url_string);
PopUpOk(buf);
p->url = @http_parse_url(buf);
}
if (!p->url->port) {
PopUpOk(url_string);
while (1)
Sleep(1);
}
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;
// FIXME: A bug in TLS implementation chops off the last byte, which sometimes
// breaks the tokenizer. Let's add '>' at the end of the buffer to workaround
// this for now.
I64 content_length = 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;
}
}
I64 content_pos = content_length;
while (MemCmp(buffer + content_pos, "/html", 5) != 0)
content_pos--;
StrCpy(buffer + content_pos, "/html>");
if (buffer[StrLen(buffer) - 1] == 'l')
StrCpy(buffer + StrLen(buffer), ">");
/*
DocClear(DocPut);
DocPrint(DocPut, "\dWW\d\dFG,8\d");
DocPutS(DocPut, buffer);
PressAKey;
*/
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);
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
}
U0 @cmd_go_to_url(CTask *doc) {
U8 *url_string = @popup_get_str("Web - World Wide Web browser for TempleOS",
"Go to URL: ");
Navigate(doc, url_string);
}
U0 Web() {
if (!FileFind("C:/Web"))
DirMk("C:/Web");
if (!FileFind("C:/Web/Cache"))
DirMk("C:/Web/Cache");
@task_doc_push('Web');
@init_new_websession(DocPut);
@cmd_go_to_url(DocPut);
while (1) {
GetStr;
}
DocClear(DocPut);
@task_doc_pop;
}