From f824ab8af4d3d2e34bd59b860b9c6d5568c3bb44 Mon Sep 17 00:00:00 2001 From: John-Mark Bell Date: Sat, 3 Nov 2012 23:19:28 +0000 Subject: Port save complete to libdom. --- amiga/Makefile.target | 2 +- amiga/file.c | 32 +- amiga/save_complete.c | 116 ---- amiga/save_complete.h | 32 - atari/Makefile.target | 2 +- atari/global_evnt.c | 2 +- atari/save.c | 88 --- beos/Makefile.target | 6 +- beos/save_complete.cpp | 85 --- cocoa/Makefile.target | 1 - cocoa/save.m | 37 -- desktop/save_complete.c | 1506 +++++++++++++++++++++++++------------------ desktop/save_complete.h | 29 +- framebuffer/Makefile.target | 2 +- framebuffer/save.c | 48 -- gtk/Makefile.target | 2 +- gtk/gui.c | 3 + gtk/save.c | 81 --- gtk/scaffolding.c | 3 +- monkey/utils.c | 15 - riscos/save.c | 67 +- windows/gui.c | 22 - 22 files changed, 961 insertions(+), 1220 deletions(-) delete mode 100755 amiga/save_complete.c delete mode 100755 amiga/save_complete.h delete mode 100644 atari/save.c delete mode 100644 beos/save_complete.cpp delete mode 100644 cocoa/save.m delete mode 100644 framebuffer/save.c delete mode 100644 gtk/save.c diff --git a/amiga/Makefile.target b/amiga/Makefile.target index c4db9a373..5b11ec018 100644 --- a/amiga/Makefile.target +++ b/amiga/Makefile.target @@ -75,7 +75,7 @@ EXETARGET := NetSurf S_AMIGA := gui.c tree.c history.c hotlist.c schedule.c file.c \ thumbnail.c misc.c bitmap.c font.c filetype.c utf8.c login.c \ plotters.c object.c menu.c save_pdf.c arexx.c version.c \ - cookies.c context_menu.c clipboard.c save_complete.c \ + cookies.c context_menu.c clipboard.c \ launch.c search.c history_local.c download.c iff_dr2d.c \ sslcert.c gui_options.c print.c theme.c drag.c icon.c system_colour.c \ datatypes.c dt_picture.c dt_anim.c dt_sound.c plugin_hack.c \ diff --git a/amiga/file.c b/amiga/file.c index c2e4f13ad..8157180ec 100644 --- a/amiga/file.c +++ b/amiga/file.c @@ -99,6 +99,36 @@ void ami_file_open(struct gui_window_2 *gwin) } } +static void ami_file_set_type(const char *path, lwc_string *mime_type) +{ + content_type type = content_factory_type_from_mime_type(mime_type); + const char *default_type; + + switch(type) + { + case CONTENT_HTML: + default_type = "html"; + break; + case CONTENT_CSS: + default_type = "css"; + break; + default: + default_type = NULL; + break; + } + + if (default_type != NULL) { + struct DiskObject *dobj = NULL; + + dobj = GetIconTags(NULL,ICONGETA_GetDefaultName,default_type, + ICONGETA_GetDefaultType,WBPROJECT, + TAG_DONE); + + PutIconTags(path, dobj, + ICONPUTA_NotifyWorkbench, TRUE, TAG_DONE); + } +} + void ami_file_save(int type, char *fname, struct Window *win, struct hlcache_handle *object, struct hlcache_handle *favicon, struct selection *sel) @@ -134,7 +164,7 @@ void ami_file_save(int type, char *fname, struct Window *win, if(lock = CreateDir(fname)) { UnLock(lock); - save_complete(object, fname); + save_complete(object, fname, ami_file_set_type); amiga_icon_superimpose_favicon(fname, favicon, NULL); } break; diff --git a/amiga/save_complete.c b/amiga/save_complete.c deleted file mode 100755 index dad952c0b..000000000 --- a/amiga/save_complete.c +++ /dev/null @@ -1,116 +0,0 @@ -/* - * Copyright 2004 John M Bell - * Copyright 2004-2007 James Bursa - * Copyright 2008 Chris Young - * Copyright 2009 Mark Benjamin - * - * This file is part of NetSurf, http://www.netsurf-browser.org/ - * - * NetSurf is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. - * - * NetSurf is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#include -#include -#include -#include -#include "desktop/save_complete.h" -#include "utils/utils.h" -#include -#include -#include "content/content.h" - -/** -* conducts the filesystem save appropriate to the gui -* \param path save path -* \param filename name of file to save -* \param len data length -* \param sourcedata pointer to data to save, NULL when all data in c -* \param type content type -* \return true for success -*/ - -bool save_complete_gui_save(const char *path, const char *filename, size_t len, - const char *sourcedata, lwc_string *mime_type) -{ - content_type type = content_factory_type_from_mime_type(mime_type); - int res; - int namelen; - char deftype[5]; - struct DiskObject *dobj = NULL; - namelen = strlen(path) + strlen(filename) + 2; - char *fullpath = malloc(namelen); - if (!fullpath) { - warn_user("NoMemory", 0); - return false; - } - snprintf(fullpath, namelen, "%s/%s", path, filename); - FILE *f = fopen(fullpath, "w"); - if (f == NULL) - return false; - res = fwrite(sourcedata, len, 1, f); - fclose(f); - switch(type) - { - case CONTENT_HTML: - strcpy(deftype,"html"); - break; - case CONTENT_CSS: - strcpy(deftype,"css"); - break; - default: - free(fullpath); - return true; - break; - } - - dobj = GetIconTags(NULL,ICONGETA_GetDefaultName,deftype, - ICONGETA_GetDefaultType,WBPROJECT, - TAG_DONE); - - PutIconTags(fullpath, dobj, - ICONPUTA_NotifyWorkbench, TRUE, TAG_DONE); - free(fullpath); - if (res != 1) - return false; - return true; -} - -/** -* wrapper for lib function htmlSaveFileFormat; front sets path from -* path + filename in a filesystem-specific way -*/ - -int save_complete_htmlSaveFileFormat(const char *path, const char *filename, - xmlDocPtr cur, const char *encoding, int format) -{ - int ret; - int len = strlen(path) + strlen(filename) + 2; - struct DiskObject *dobj = NULL; - char *fullpath = malloc(len); - if (!fullpath){ - warn_user("NoMemory", 0); - return -1; - } - snprintf(fullpath, len, "%s/%s", path, filename); - ret = htmlSaveFileFormat(fullpath, cur, encoding, format); - dobj = GetIconTags(NULL,ICONGETA_GetDefaultName, "html", - ICONGETA_GetDefaultType,WBPROJECT, - TAG_DONE); - - PutIconTags(fullpath, dobj, - ICONPUTA_NotifyWorkbench, TRUE, TAG_DONE); - - free(fullpath); - return ret; -} - diff --git a/amiga/save_complete.h b/amiga/save_complete.h deleted file mode 100755 index cb6c26643..000000000 --- a/amiga/save_complete.h +++ /dev/null @@ -1,32 +0,0 @@ -/* - * Copyright 2004 John M Bell - * Copyright 2008 Chris Young - * - * This file is part of NetSurf, http://www.netsurf-browser.org/ - * - * NetSurf is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. - * - * NetSurf is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -/** \file - * Save HTML document with dependencies (interface). - */ - -#ifndef AMIGA_SAVE_COMPLETE_H -#define AMIGA_SAVE_COMPLETE_H - -#include "content/content.h" - -void save_complete_init(void); -bool save_complete(hlcache_handle *c, const char *path); - -#endif diff --git a/atari/Makefile.target b/atari/Makefile.target index bccb15c48..844abfe31 100644 --- a/atari/Makefile.target +++ b/atari/Makefile.target @@ -82,7 +82,7 @@ S_ATARI := gui.c findfile.c filetype.c misc.c bitmap.c schedule.c \ redrawslots.c encoding.c \ browser_win.c toolbar.c statusbar.c browser.c \ global_evnt.c osspec.c dragdrop.c system_colour.c \ - ctxmenu.c save.c settings.c + ctxmenu.c settings.c S_ATARI := $(addprefix atari/,$(S_ATARI)) # This is the final source build list diff --git a/atari/global_evnt.c b/atari/global_evnt.c index 0c9dfdc1e..3b15af877 100755 --- a/atari/global_evnt.c +++ b/atari/global_evnt.c @@ -176,7 +176,7 @@ static void __CDECL menu_save_page(WINDOW *win, int item, int title, void *data) } while( !is_folder && path != NULL ); if( path != NULL ){ - save_complete( input_window->browser->bw->current_content, path ); + save_complete( input_window->browser->bw->current_content, path, NULL ); } } diff --git a/atari/save.c b/atari/save.c deleted file mode 100644 index 83e4e410c..000000000 --- a/atari/save.c +++ /dev/null @@ -1,88 +0,0 @@ -/* - * Copyright 2009 Mark Benjamin - * - * This file is part of NetSurf, http://www.netsurf-browser.org/ - * - * NetSurf is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. - * - * NetSurf is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#include -#include -#include -#include - -#include "content/content.h" -#include "desktop/save_complete.h" -#include "utils/utils.h" - -/* - This code was simply taken from GTK frontend. It requires adjustment - within the core or frontend to work well. - ( mime type detection fails on load of the saved webpage, that's because - no file extension is saved. ) -*/ - -/** -* conducts the filesystem save appropriate to the gui -* \param path save path -* \param filename name of file to save -* \param len data length -* \param sourcedata pointer to data to save -* \param type content type -* \return true for success -*/ - -bool save_complete_gui_save(const char *path, const char *filename, - size_t len, const char *sourcedata, lwc_string *mime_type) -{ - int res; - int namelen; - namelen = strlen(path) + strlen(filename) + 2; /* '/', '\0' */ - char *fullpath = malloc(namelen); - if (!fullpath) { - warn_user("NoMemory", 0); - return false; - } - snprintf(fullpath, namelen, "%s/%s", path, filename); - FILE *f; - f = fopen(fullpath, "wb"); - free(fullpath); - if (f == NULL) - return false; - res = fwrite(sourcedata, len, 1, f); - fclose(f); - if (res != 1) - return false; - return true; -} - -/** -* wrapper for lib function htmlSaveFileFormat; front sets path from path -* + filename in a filesystem-specific way -*/ - -int save_complete_htmlSaveFileFormat(const char *path, const char *filename, - xmlDocPtr cur, const char *encoding, int format) -{ - int ret; - int len = strlen(path) + strlen(filename) + 2; - char *fullpath = malloc(len); - if (fullpath == NULL) { - warn_user("NoMemory", 0); - return -1; - } - snprintf(fullpath, len, "%s/%s", path, filename); - ret = htmlSaveFileFormat(fullpath, cur, encoding, format); - free(fullpath); - return ret; -} diff --git a/beos/Makefile.target b/beos/Makefile.target index be58be4a7..b1d1eaab5 100644 --- a/beos/Makefile.target +++ b/beos/Makefile.target @@ -85,8 +85,8 @@ # S_BEOS are sources purely for the BeOS build S_BEOS := about.cpp bitmap.cpp fetch_rsrc.cpp \ - filetype.cpp font.cpp gui.cpp login.cpp \ - gui_options.cpp plotters.cpp save_complete.cpp \ + filetype.cpp font.cpp gui.cpp login.cpp \ + gui_options.cpp plotters.cpp \ scaffolding.cpp search.cpp schedule.cpp \ thumbnail.cpp treeview.cpp throbber.cpp \ window.cpp system_colour.cpp @@ -134,4 +134,4 @@ install-beos: # Package target # ---------------------------------------------------------------------------- -package-beos: \ No newline at end of file +package-beos: diff --git a/beos/save_complete.cpp b/beos/save_complete.cpp deleted file mode 100644 index 19306dc21..000000000 --- a/beos/save_complete.cpp +++ /dev/null @@ -1,85 +0,0 @@ -/* - * Copyright 2008 François Revol - * Copyright 2009 Mark Benjamin - * - * This file is part of NetSurf, http://www.netsurf-browser.org/ - * - * NetSurf is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. - * - * NetSurf is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#define __STDBOOL_H__ 1 -#include -#include -#include -#include -extern "C" { -#include "content/content.h" -#include "desktop/save_complete.h" -#include "utils/utils.h" -} - -/** -* conducts the filesystem save appropriate to the gui -* \param path save path -* \param filename name of file to save -* \param len data length -* \param sourcedata pointer to data to save -* \param type content type -* \return true for success -*/ - -bool save_complete_gui_save(const char *path, const char *filename, - size_t len, const char *sourcedata, lwc_string *mime_type) -{ - int res; - int namelen; - namelen = strlen(path) + strlen(filename) + 2; /* '/', '\0' */ - char *fullpath = (char *)malloc(namelen); - if (!fullpath) { - warn_user("NoMemory", 0); - return false; - } - snprintf(fullpath, namelen, "%s/%s", path, filename); - FILE *f; - f = fopen(fullpath, "wb"); - free(fullpath); - if (f == NULL) - return false; - res = fwrite(sourcedata, len, 1, f); - fclose(f); - if (res != 1) - return false; - return true; -} - -/** -* wrapper for lib function htmlSaveFileFormat; front sets path from path -* + filename in a filesystem-specific way -*/ - -int save_complete_htmlSaveFileFormat(const char *path, const char *filename, - xmlDocPtr cur, const char *encoding, int format) -{ - int ret; - int len = strlen(path) + strlen(filename) + 2; - char *fullpath = (char *)malloc(len); - if (fullpath == NULL) { - warn_user("NoMemory", 0); - return -1; - } - snprintf(fullpath, len, "%s/%s", path, filename); - ret = htmlSaveFileFormat(fullpath, cur, encoding, format); - free(fullpath); - return ret; -} - diff --git a/cocoa/Makefile.target b/cocoa/Makefile.target index fa1f7a095..fd78e5e11 100644 --- a/cocoa/Makefile.target +++ b/cocoa/Makefile.target @@ -95,7 +95,6 @@ S_COCOA := \ font.m \ gui.m \ plotter.m \ - save.m \ schedule.m \ selection.m \ thumbnail.m \ diff --git a/cocoa/save.m b/cocoa/save.m deleted file mode 100644 index 9ee2f4cd8..000000000 --- a/cocoa/save.m +++ /dev/null @@ -1,37 +0,0 @@ -/* - * Copyright 2011 Sven Weidauer - * - * This file is part of NetSurf, http://www.netsurf-browser.org/ - * - * NetSurf is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. - * - * NetSurf is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#import - -#import "desktop/save_complete.h" - -#define UNIMPL() NSLog( @"Function '%s' unimplemented", __func__ ) - -bool save_complete_gui_save(const char *path, const char *filename, - size_t len, const char *sourcedata, lwc_string *mime_type) -{ - UNIMPL(); - return false; -} - -int save_complete_htmlSaveFileFormat(const char *path, const char *filename, - xmlDocPtr cur, const char *encoding, int format) -{ - UNIMPL(); - return 0; -} diff --git a/desktop/save_complete.c b/desktop/save_complete.c index 0ac64b515..42da86752 100644 --- a/desktop/save_complete.c +++ b/desktop/save_complete.c @@ -1,5 +1,5 @@ /* - * Copyright 2004 John M Bell + * Copyright 2012 John-Mark Bell * Copyright 2004-2007 James Bursa * * This file is part of NetSurf, http://www.netsurf-browser.org/ @@ -30,492 +30,251 @@ #include #include #include + #include -#include "utils/config.h" + #include "content/content.h" #include "content/hlcache.h" #include "css/css.h" -#include "render/box.h" #include "desktop/save_complete.h" +#include "render/box.h" +#include "render/html.h" #include "utils/log.h" -#include "utils/url.h" +#include "utils/nsurl.h" #include "utils/utils.h" -#include "render/html.h" regex_t save_complete_import_re; /** An entry in save_complete_list. */ -struct save_complete_entry { +typedef struct save_complete_entry { hlcache_handle *content; struct save_complete_entry *next; /**< Next entry in list */ -}; - -static bool save_complete_html(hlcache_handle *c, const char *path, - bool index, struct save_complete_entry **list); -static bool save_imported_sheets(struct nscss_import *imports, uint32_t count, - const char *path, struct save_complete_entry **list); -static char * rewrite_stylesheet_urls(const char *source, unsigned int size, - int *osize, const char *base, - struct save_complete_entry *list); -static bool rewrite_document_urls(xmlDoc *doc, const char *base, - struct save_complete_entry *list); -static bool rewrite_urls(xmlNode *n, const char *base, - struct save_complete_entry *list); -static bool rewrite_url(xmlNode *n, const char *attr, const char *base, - struct save_complete_entry *list); -static bool save_complete_list_add(hlcache_handle *content, - struct save_complete_entry **list); -static hlcache_handle * save_complete_list_find(const char *url, - struct save_complete_entry *list); -static bool save_complete_list_check(hlcache_handle *content, - struct save_complete_entry *list); -/* static void save_complete_list_dump(void); */ -static bool save_complete_inventory(const char *path, - struct save_complete_entry *list); - -/** - * Save an HTML page with all dependencies. - * - * \param c CONTENT_HTML to save - * \param path directory to save to (must exist) - * \return true on success, false on error and error reported - */ +} save_complete_entry; -bool save_complete(hlcache_handle *c, const char *path) -{ - bool result; - struct save_complete_entry *list = NULL; - - result = save_complete_html(c, path, true, &list); +typedef struct save_complete_ctx { + const char *path; + save_complete_entry *list; + save_complete_set_type_cb set_type; - if (result) - result = save_complete_inventory(path, list); + nsurl *base; + FILE *fp; + enum { STATE_NORMAL, STATE_IN_STYLE } iter_state; +} save_complete_ctx; - /* free save_complete_list */ - while (list) { - struct save_complete_entry *next = list->next; - free(list); - list = next; - } +typedef enum { + EVENT_ENTER, + EVENT_LEAVE +} save_complete_event_type; - return result; -} +static bool save_complete_save_html(save_complete_ctx *ctx, hlcache_handle *c, + bool index); +static bool save_complete_save_imported_sheets(save_complete_ctx *ctx, + struct nscss_import *imports, uint32_t import_count); -/** - * Save an HTML page with all dependencies, recursing through imported pages. - * - * \param c CONTENT_HTML to save - * \param path directory to save to (must exist) - * \param index true to save as "index" - * \return true on success, false on error and error reported - */ -bool save_complete_html(hlcache_handle *c, const char *path, bool index, - struct save_complete_entry **list) +static void save_complete_ctx_initialise(save_complete_ctx *ctx, + const char *path, save_complete_set_type_cb set_type) { - struct html_stylesheet *sheets; - struct content_html_object *object; - char filename[256]; - unsigned int i, count; - xmlDocPtr doc = NULL; - bool res; - - if (content_get_type(c) != CONTENT_HTML) - return false; - - if (save_complete_list_check(c, *list)) - return true; - - /* save stylesheets, ignoring the base and adblocking sheets */ - sheets = html_get_stylesheets(c, &count); - - for (i = STYLESHEET_START; i != count; i++) { - hlcache_handle *css; - const char *css_data; - unsigned long css_size; - char *source; - int source_len; - struct nscss_import *imports; - uint32_t import_count; - lwc_string *type; - - if (sheets[i].type == HTML_STYLESHEET_INTERNAL) { - if (save_imported_sheets( - sheets[i].data.internal->imports, - sheets[i].data.internal->import_count, - path, list) == false) - return false; - - continue; - } - - css = sheets[i].data.external; - - if (!css) - continue; - if (save_complete_list_check(css, *list)) - continue; - - if (!save_complete_list_add(css, list)) { - warn_user("NoMemory", 0); - return false; - } - - imports = nscss_get_imports(css, &import_count); - if (!save_imported_sheets(imports, import_count, path, list)) - return false; - - snprintf(filename, sizeof filename, "%p", css); - - css_data = content_get_source_data(css, &css_size); - - source = rewrite_stylesheet_urls(css_data, css_size, - &source_len, nsurl_access(hlcache_handle_get_url(css)), - *list); - if (!source) { - warn_user("NoMemory", 0); - return false; - } - - type = content_get_mime_type(css); - if (type == NULL) { - free(source); - return false; - } - - res = save_complete_gui_save(path, filename, source_len, - source, type); - - lwc_string_unref(type); - free(source); - - if (res == false) - return false; - } - - /* save objects */ - object = html_get_objects(c, &count); - - for (; object != NULL; object = object->next) { - hlcache_handle *obj = object->content; - const char *obj_data; - unsigned long obj_size; - lwc_string *type; - - if (obj == NULL || content_get_type(obj) == CONTENT_NONE) - continue; - - obj_data = content_get_source_data(obj, &obj_size); - - if (obj_data == NULL) - continue; - - if (save_complete_list_check(obj, *list)) - continue; - - if (!save_complete_list_add(obj, list)) { - warn_user("NoMemory", 0); - return false; - } - - if (content_get_type(obj) == CONTENT_HTML) { - if (!save_complete_html(obj, path, false, list)) - return false; - continue; - } - - snprintf(filename, sizeof filename, "%p", obj); - - type = content_get_mime_type(obj); - if (type == NULL) - return false; - - res = save_complete_gui_save(path, filename, - obj_size, obj_data, type); - - lwc_string_unref(type); - - if(res == false) - return false; - } + ctx->path = path; + ctx->list = NULL; + ctx->set_type = set_type; +} - /* create shiny XML document from the content source */ - - { - unsigned long html_size; - const char *html_source; - xmlChar *terminated_html_source; - html_source = content_get_source_data(c, &html_size); - - terminated_html_source = malloc(html_size + 1); - if (terminated_html_source != NULL) { - memcpy(terminated_html_source, html_source, html_size); - terminated_html_source[html_size] = '\0'; - doc = htmlParseDoc(terminated_html_source, NULL); - free(terminated_html_source); - } - - } - - if (doc == NULL) { - warn_user("NoMemory", 0); - return false; - } +static void save_complete_ctx_finalise(save_complete_ctx *ctx) +{ + save_complete_entry *list = ctx->list; - /* rewrite all urls we know about */ - if (!rewrite_document_urls(doc, nsurl_access(html_get_base_url(c)), - *list)) { - xmlFreeDoc(doc); - warn_user("NoMemory", 0); - return false; + while (list != NULL) { + save_complete_entry *next = list->next; + free(list); + list = next; } +} - /* save the html file out last of all */ - if (index) - snprintf(filename, sizeof filename, "index"); - else - snprintf(filename, sizeof filename, "%p", c); - - errno = 0; - if (save_complete_htmlSaveFileFormat(path, filename, doc, 0, 0) == -1) { - if (errno) - warn_user("SaveError", strerror(errno)); - else - warn_user("SaveError", "htmlSaveFileFormat failed"); +static bool save_complete_ctx_add_content(save_complete_ctx *ctx, + hlcache_handle *content) +{ + save_complete_entry *entry; - xmlFreeDoc(doc); + entry = malloc(sizeof (*entry)); + if (entry == NULL) return false; - } - xmlFreeDoc(doc); + entry->content = content; + entry->next = ctx->list; + ctx->list = entry; return true; } -/** - * Save stylesheets imported by a CONTENT_CSS. - * - * \param imports Array of imports - * \param count Number of imports in list - * \param path Path to save to - * \return true on success, false on error and error reported - */ -bool save_imported_sheets(struct nscss_import *imports, uint32_t count, - const char *path, struct save_complete_entry **list) +static hlcache_handle *save_complete_ctx_find_content(save_complete_ctx *ctx, + const nsurl *url) { - char filename[256]; - unsigned int j; - char *source; - int source_len; - bool res; - - for (j = 0; j != count; j++) { - hlcache_handle *css = imports[j].c; - const char *css_data; - unsigned long css_size; - struct nscss_import *child_imports; - uint32_t child_import_count; - lwc_string *type; - - if (css == NULL) - continue; - if (save_complete_list_check(css, *list)) - continue; + save_complete_entry *entry; - if (!save_complete_list_add(css, list)) { - warn_user("NoMemory", 0); - return false; - } + for (entry = ctx->list; entry != NULL; entry = entry->next) + if (nsurl_compare(url, + hlcache_handle_get_url(entry->content), + NSURL_COMPLETE)) + return entry->content; - child_imports = nscss_get_imports(css, &child_import_count); - if (!save_imported_sheets(child_imports, child_import_count, - path, list)) - return false; + return NULL; +} - snprintf(filename, sizeof filename, "%p", css); - css_data = content_get_source_data(css, &css_size); +static bool save_complete_ctx_has_content(save_complete_ctx *ctx, + hlcache_handle *content) +{ + save_complete_entry *entry; - source = rewrite_stylesheet_urls(css_data, css_size, - &source_len, nsurl_access(hlcache_handle_get_url(css)), - *list); - if (!source) { - warn_user("NoMemory", 0); - return false; - } + for (entry = ctx->list; entry != NULL; entry = entry->next) + if (entry->content == content) + return true; - if (lwc_intern_string("text/css", SLEN("text/css"), &type) != - lwc_error_ok) { - free(source); - warn_user("NoMemory", 0); - return false; - } + return false; +} - res = save_complete_gui_save(path, filename, source_len, - source, type); +static bool save_complete_save_buffer(save_complete_ctx *ctx, + const char *leafname, const char *data, size_t data_len, + lwc_string *mime_type) +{ + FILE *fp; + bool error; + char fullpath[PATH_MAX]; - lwc_string_unref(type); - free(source); + strncpy(fullpath, ctx->path, sizeof fullpath); + error = path_add_part(fullpath, sizeof fullpath, leafname); + if (error == false) { + warn_user("NoMemory", NULL); + return false; + } - if (res == false) - return false; + fp = fopen(fullpath, "wb"); + if (fp == NULL) { + LOG(("fopen(): errno = %i", errno)); + warn_user("SaveError", strerror(errno)); + return false; } - return true; -} + fwrite(data, sizeof(*data), data_len, fp); + fclose(fp); -/** - * Initialise the save_complete module. - */ + if (ctx->set_type != NULL) + ctx->set_type(fullpath, mime_type); -void save_complete_init(void) -{ - /* Match an @import rule - see CSS 2.1 G.1. */ - regcomp_wrapper(&save_complete_import_re, - "@import" /* IMPORT_SYM */ - "[ \t\r\n\f]*" /* S* */ - /* 1 */ - "(" /* [ */ - /* 2 3 */ - "\"(([^\"]|[\\]\")*)\"" /* STRING (approximated) */ - "|" - /* 4 5 */ - "'(([^']|[\\]')*)'" - "|" /* | */ - "url\\([ \t\r\n\f]*" /* URI (approximated) */ - /* 6 7 */ - "\"(([^\"]|[\\]\")*)\"" - "[ \t\r\n\f]*\\)" - "|" - "url\\([ \t\r\n\f]*" - /* 8 9 */ - "'(([^']|[\\]')*)'" - "[ \t\r\n\f]*\\)" - "|" - "url\\([ \t\r\n\f]*" - /* 10 */ - "([^) \t\r\n\f]*)" - "[ \t\r\n\f]*\\)" - ")", /* ] */ - REG_EXTENDED | REG_ICASE); + return true; } - /** * Rewrite stylesheet \@import rules for save complete. * - * @param source stylesheet source - * @param size size of source - * @param osize updated with the size of the result - * @param base url of stylesheet - * @return converted source, or 0 on out of memory + * \param source stylesheet source + * \param size size of source + * \param base url of stylesheet + * \param osize updated with the size of the result + * \return converted source, or NULL on out of memory */ -char * rewrite_stylesheet_urls(const char *source, unsigned int size, - int *osize, const char *base, - struct save_complete_entry *list) +static char *save_complete_rewrite_stylesheet_urls(save_complete_ctx *ctx, + const char *source, unsigned long size, const nsurl *base, + unsigned long *osize) { - char *res; - const char *url; - char *url2; - char buf[20]; - unsigned int offset = 0; - int url_len = 0; - hlcache_handle *content; - int m; - unsigned int i; + char *rewritten; + unsigned long offset = 0; unsigned int imports = 0; - regmatch_t match[11]; - url_func_result result; + nserror error; - /* count number occurences of @import to (over)estimate result size */ + /* count number occurrences of @import to (over)estimate result size */ /* can't use strstr because source is not 0-terminated string */ - for (i = 0; 7 < size && i != size - 7; i++) { - if (source[i] == '@' && - tolower(source[i + 1]) == 'i' && - tolower(source[i + 2]) == 'm' && - tolower(source[i + 3]) == 'p' && - tolower(source[i + 4]) == 'o' && - tolower(source[i + 5]) == 'r' && - tolower(source[i + 6]) == 't') + for (offset = 0; SLEN("@import") < size && + offset <= size - SLEN("@import"); offset++) { + if (source[offset] == '@' && + tolower(source[offset + 1]) == 'i' && + tolower(source[offset + 2]) == 'm' && + tolower(source[offset + 3]) == 'p' && + tolower(source[offset + 4]) == 'o' && + tolower(source[offset + 5]) == 'r' && + tolower(source[offset + 6]) == 't') imports++; } - res = malloc(size + imports * 20); - if (!res) - return 0; + rewritten = malloc(size + imports * 20); + if (rewritten == NULL) + return NULL; *osize = 0; + offset = 0; while (offset < size) { - m = regexec(&save_complete_import_re, source + offset, + const char *import_url = NULL; + char *import_url_copy; + int import_url_len = 0; + nsurl *url = NULL; + regmatch_t match[11]; + int m = regexec(&save_complete_import_re, source + offset, 11, match, 0); if (m) break; - /*for (unsigned int i = 0; i != 11; i++) { - if (match[i].rm_so == -1) - continue; - fprintf(stderr, "%i: '%.*s'\n", i, - match[i].rm_eo - match[i].rm_so, - source + offset + match[i].rm_so); - }*/ - - url = 0; if (match[2].rm_so != -1) { - url = source + offset + match[2].rm_so; - url_len = match[2].rm_eo - match[2].rm_so; + import_url = source + offset + match[2].rm_so; + import_url_len = match[2].rm_eo - match[2].rm_so; } else if (match[4].rm_so != -1) { - url = source + offset + match[4].rm_so; - url_len = match[4].rm_eo - match[4].rm_so; + import_url = source + offset + match[4].rm_so; + import_url_len = match[4].rm_eo - match[4].rm_so; } else if (match[6].rm_so != -1) { - url = source + offset + match[6].rm_so; - url_len = match[6].rm_eo - match[6].rm_so; + import_url = source + offset + match[6].rm_so; + import_url_len = match[6].rm_eo - match[6].rm_so; } else if (match[8].rm_so != -1) { - url = source + offset + match[8].rm_so; - url_len = match[8].rm_eo - match[8].rm_so; + import_url = source + offset + match[8].rm_so; + import_url_len = match[8].rm_eo - match[8].rm_so; } else if (match[10].rm_so != -1) { - url = source + offset + match[10].rm_so; - url_len = match[10].rm_eo - match[10].rm_so; + import_url = source + offset + match[10].rm_so; + import_url_len = match[10].rm_eo - match[10].rm_so; } - assert(url); + assert(import_url != NULL); - url2 = strndup(url, url_len); - if (!url2) { - free(res); - return 0; + import_url_copy = strndup(import_url, import_url_len); + if (import_url_copy == NULL) { + free(rewritten); + return NULL; } - result = url_join(url2, base, (char**)&url); - free(url2); - if (result == URL_FUNC_NOMEM) { - free(res); - return 0; + + error = nsurl_join(base, import_url_copy, &url); + free(import_url_copy); + if (error == NSERROR_NOMEM) { + free(rewritten); + return NULL; } /* copy data before match */ - memcpy(res + *osize, source + offset, match[0].rm_so); + memcpy(rewritten + *osize, source + offset, match[0].rm_so); *osize += match[0].rm_so; - if (result == URL_FUNC_OK) { - content = save_complete_list_find(url, list); - if (content) { + if (url != NULL) { + hlcache_handle *content; + content = save_complete_ctx_find_content(ctx, url); + if (content != NULL) { /* replace import */ + char buf[64]; snprintf(buf, sizeof buf, "@import '%p'", content); - memcpy(res + *osize, buf, strlen(buf)); + memcpy(rewritten + *osize, buf, strlen(buf)); *osize += strlen(buf); } else { /* copy import */ - memcpy(res + *osize, source + offset + match[0].rm_so, + memcpy(rewritten + *osize, + source + offset + match[0].rm_so, match[0].rm_eo - match[0].rm_so); *osize += match[0].rm_eo - match[0].rm_so; } - } - else { + nsurl_unref(url); + } else { /* copy import */ - memcpy(res + *osize, source + offset + match[0].rm_so, + memcpy(rewritten + *osize, + source + offset + match[0].rm_so, match[0].rm_eo - match[0].rm_so); *osize += match[0].rm_eo - match[0].rm_so; } @@ -526,308 +285,771 @@ char * rewrite_stylesheet_urls(const char *source, unsigned int size, /* copy rest of source */ if (offset < size) { - memcpy(res + *osize, source + offset, size - offset); + memcpy(rewritten + *osize, source + offset, size - offset); *osize += size - offset; } - return res; + return rewritten; } - -/** - * Rewrite URLs in a HTML document to be relative. - * - * \param doc root of the document tree - * \param base base url of document - * \return true on success, false on out of memory - */ - -bool rewrite_document_urls(xmlDoc *doc, const char *base, - struct save_complete_entry *list) +static bool save_complete_save_stylesheet(save_complete_ctx *ctx, + hlcache_handle *css) { - xmlNode *node; + const char *css_data; + unsigned long css_size; + char *source; + unsigned long source_len; + struct nscss_import *imports; + uint32_t import_count; + lwc_string *type; + char filename[32]; + bool result; - for (node = doc->children; node; node = node->next) - if (node->type == XML_ELEMENT_NODE) - if (!rewrite_urls(node, base, list)) - return false; + if (save_complete_ctx_has_content(ctx, css)) + return true; - return true; -} + if (save_complete_ctx_add_content(ctx, css) == false) { + warn_user("NoMemory", 0); + return false; + } + imports = nscss_get_imports(css, &import_count); + if (save_complete_save_imported_sheets(ctx, + imports, import_count) == false) + return false; -/** - * Traverse tree, rewriting URLs as we go. - * - * \param n xmlNode of type XML_ELEMENT_NODE to rewrite - * \param base base url of document - * \return true on success, false on out of memory - * - * URLs in the tree rooted at element n are rewritten. - */ + css_data = content_get_source_data(css, &css_size); + source = save_complete_rewrite_stylesheet_urls(ctx, css_data, css_size, + hlcache_handle_get_url(css), &source_len); + if (source == NULL) { + warn_user("NoMemory", 0); + return false; + } -bool rewrite_urls(xmlNode *n, const char *base, - struct save_complete_entry *list) -{ - xmlNode *child; + type = content_get_mime_type(css); + if (type == NULL) { + free(source); + return false; + } - assert(n->type == XML_ELEMENT_NODE); + snprintf(filename, sizeof filename, "%p", css); - /** - * We only need to consider the following cases: - * - * Attribute: Elements: - * - * 1) data - * 2) href - * 3) src