/* * This file is part of LibNSLayout's tests * Licensed under the ISC License, http://opensource.org/licenses/ISC * Copyright 2015 Michael Drake */ #include #include #include #include #include #include #include #include #ifndef UNUSED #define UNUSED(x) (void)(x) #endif static nslayout_error test_loader_nslayout_test_callback( nslayout_layout *layout, void *pw, nslayout_request *req) { UNUSED(req); UNUSED(layout); UNUSED(pw); return NSLAYOUT_OK; } struct test_loader_buffer { unsigned char *buf; size_t len; size_t pos; }; struct test_loader_ctx { struct test_loader_buffer *html; dom_hubbub_parser *parser; dom_document *doc; css_select_ctx *css_ctx; css_stylesheet *css_sheet; }; static bool test_loader_doc_load_start( size_t chunk_length, struct test_loader_ctx *load_ctx) { dom_hubbub_parser_params params; dom_hubbub_error error; params.enc = NULL; params.fix_enc = true; params.enable_script = false; params.msg = NULL; params.script = NULL; params.ctx = NULL; params.daf = NULL; /* Create Hubbub parser */ error = dom_hubbub_parser_create(¶ms, &load_ctx->parser, &load_ctx->doc); if (error != DOM_HUBBUB_OK) { return false; } /* Find length of first chunk */ if (chunk_length > (load_ctx->html->len - load_ctx->html->pos)) chunk_length = load_ctx->html->len - load_ctx->html->pos; /* Load first chunk */ error = dom_hubbub_parser_parse_chunk(load_ctx->parser, load_ctx->html->buf + load_ctx->html->pos, chunk_length); load_ctx->html->pos += chunk_length; if (error != DOM_HUBBUB_OK) { dom_hubbub_parser_destroy(load_ctx->parser); printf("Parsing errors occur\n"); return false; } return true; } bool test_loader_doc_load_next( struct test_loader_ctx *load_ctx, size_t chunk_length, bool *complete) { dom_hubbub_error error; /* Find length of chunk */ if (chunk_length > (load_ctx->html->len - load_ctx->html->pos)) chunk_length = load_ctx->html->len - load_ctx->html->pos; if (chunk_length > 0) { /* Parse the chunk */ printf(" Text: %.*s\n", (int)chunk_length, load_ctx->html->buf + load_ctx->html->pos); error = dom_hubbub_parser_parse_chunk(load_ctx->parser, load_ctx->html->buf + load_ctx->html->pos, chunk_length); load_ctx->html->pos += chunk_length; if (error != DOM_HUBBUB_OK) { dom_hubbub_parser_destroy(load_ctx->parser); printf("Parsing errors occur\n"); return false; } } if (load_ctx->html->len != load_ctx->html->pos) { *complete = false; return true; } *complete = true; /* Done parsing file */ error = dom_hubbub_parser_completed(load_ctx->parser); if (error != DOM_HUBBUB_OK) { dom_hubbub_parser_destroy(load_ctx->parser); printf("Parsing error when construct DOM\n"); return false; } /* Finished with parser */ dom_hubbub_parser_destroy(load_ctx->parser); return true; } static css_error test_loader_resolve_url(void *pw, const char *base, lwc_string *rel, lwc_string **abs) { UNUSED(pw); UNUSED(base); /* No join implementation; just copy rel to abs for now. */ *abs = lwc_string_ref(rel); return CSS_OK; } static bool test_loader_css_fini(struct test_loader_ctx *load_ctx) { css_error css_err = CSS_OK; if (load_ctx->css_ctx != NULL) { css_err = css_select_ctx_destroy(load_ctx->css_ctx); if (css_err != CSS_OK) { printf("ERROR: css_select_ctx_destroy\n"); } } if (load_ctx->css_sheet != NULL) { css_err = css_stylesheet_destroy(load_ctx->css_sheet); if (css_err != CSS_OK) { printf("ERROR: css_stylesheet_destroy\n"); } } return (css_err == CSS_OK); } static bool test_loader_css_init(struct test_loader_ctx *load_ctx) { css_error css_err; css_stylesheet_params params; const char *ua_style = "div, p, h1, h2, h3, h4, h5 {display:block}"; params.params_version = CSS_STYLESHEET_PARAMS_VERSION_1; params.level = CSS_LEVEL_21; params.charset = "UTF-8"; params.url = "foo"; params.title = "foo"; params.allow_quirks = false; params.inline_style = false; params.resolve = test_loader_resolve_url; params.resolve_pw = NULL; params.import = NULL; params.import_pw = NULL; params.color = NULL; params.color_pw = NULL; params.font = NULL; params.font_pw = NULL; /* create a stylesheet */ css_err = css_stylesheet_create(¶ms, &load_ctx->css_sheet); if (css_err != CSS_OK) { printf("ERROR: css_stylesheet_create\n"); goto fail; } css_err = css_stylesheet_append_data(load_ctx->css_sheet, (const uint8_t *) ua_style, sizeof ua_style); if (css_err != CSS_OK && css_err != CSS_NEEDDATA) { printf("ERROR: css_stylesheet_append_data\n"); goto fail; } css_err = css_stylesheet_data_done(load_ctx->css_sheet); if (css_err != CSS_OK) { printf("ERROR: css_stylesheet_data_done\n"); goto fail; } /* Create a selection context (with no sheets added) */ css_err = css_select_ctx_create(&load_ctx->css_ctx); if (css_err != CSS_OK) { printf("ERROR: css_select_ctx_create\n"); goto fail; } css_err = css_select_ctx_append_sheet(load_ctx->css_ctx, load_ctx->css_sheet, CSS_ORIGIN_UA, CSS_MEDIA_ALL); if (css_err != CSS_OK) { printf("ERROR: css_select_ctx_append_sheet\n"); goto fail; } return true; fail: test_loader_css_fini(load_ctx); return false; } bool test_loader_load_path_to_buffer( const char *path, struct test_loader_buffer **buffer) { unsigned char *buf; long l; size_t read; FILE *f = NULL; f = fopen(path, "rb"); if (f == NULL) { printf("File could not be opened: %s\n", strerror(errno)); return false; } fseek(f, 0, SEEK_END); l = ftell(f); if (l < 0) { printf("Could not find end of file: %s\n", strerror(errno)); fclose(f); return false; } fseek(f, 0, SEEK_SET); *buffer = malloc(sizeof(struct test_loader_buffer) + l + 1); if (*buffer == NULL) { printf("Could allocate space for file\n"); fclose(f); return false; } buf = (unsigned char *)(*buffer + 1); read = fread(buf, 1, l, f); fclose(f); if (((long)read) != l) { printf("Read unexpected data length from file\n"); return false; } buf[read] = '\0'; (*buffer)->len = read; (*buffer)->buf = buf; (*buffer)->pos = 0; return true; } void test_loader_free_buffer(struct test_loader_buffer *buffer) { free(buffer); } static bool test_loader( struct test_loader_buffer *buffer, css_media_type media, size_t chunk_size) { nslayout_layout *layout = NULL; nslayout_error error; struct test_loader_ctx load_ctx; bool complete = false; bool ret = false; printf("Test loader\n"); load_ctx.parser = NULL; load_ctx.doc = NULL; load_ctx.html = buffer; load_ctx.css_sheet = NULL; load_ctx.css_ctx = NULL; printf("Starting load\n"); if (!test_loader_doc_load_start(chunk_size, &load_ctx)) { printf("ERROR: doc_load_start\n"); goto fail; } printf("Creating style context\n"); if (!test_loader_css_init(&load_ctx)) { printf("ERROR: create_style_context\n"); goto fail; } printf("Creating nsl layout\n"); error = nslayout_layout_create(load_ctx.doc, load_ctx.css_ctx, &media, test_loader_nslayout_test_callback, NULL, &layout); if (error != NSLAYOUT_OK) { goto fail; } while (!complete) { printf("Loading a chunk of the document\n"); if (!test_loader_doc_load_next(&load_ctx, chunk_size, &complete)) { printf("ERROR: doc_load_next\n"); goto fail; } } printf("Destroying layout\n"); error = nslayout_layout_destroy(layout); layout = NULL; ret = (error == NSLAYOUT_OK); fail: if (layout != NULL) { nslayout_layout_destroy(layout); } test_loader_css_fini(&load_ctx); dom_node_unref(load_ctx.doc); return ret; }