mirror of
https://git.checksum.fail/alec/Web.git
synced 2026-05-27 01:09:56 +00:00
196 lines
4.4 KiB
HolyC
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;
|
|
}
|