summaryrefslogtreecommitdiffstats
path: root/src/io
diff options
context:
space:
mode:
authorTavmjong Bah <tavmjong@free.fr>2018-10-13 07:37:26 +0000
committerTavmjong Bah <tavmjong@free.fr>2018-10-13 07:37:26 +0000
commitfaf43f2ffa88561acb95909861bb28fcdfaeb858 (patch)
tree77f397b880ec970981a754c9549b24842161855b /src/io
parentCI/AppVeyor: increase clone depth (diff)
downloadinkscape-faf43f2ffa88561acb95909861bb28fcdfaeb858.tar.gz
inkscape-faf43f2ffa88561acb95909861bb28fcdfaeb858.zip
Move some files to 'io' directory.
Diffstat (limited to 'src/io')
-rw-r--r--src/io/CMakeLists.txt56
-rw-r--r--src/io/command_line_export.h59
-rw-r--r--src/io/command_line_output.h58
-rw-r--r--src/io/commandline_io.h58
-rw-r--r--src/io/dir-util.cpp254
-rw-r--r--src/io/dir-util.h66
-rw-r--r--src/io/file.h25
-rw-r--r--src/io/open_file.h12
-rw-r--r--src/io/registrytool.cpp226
-rw-r--r--src/io/registrytool.h69
-rw-r--r--src/io/resource-manager.cpp445
-rw-r--r--src/io/resource-manager.h49
12 files changed, 1355 insertions, 22 deletions
diff --git a/src/io/CMakeLists.txt b/src/io/CMakeLists.txt
index 380b983db..c816082b0 100644
--- a/src/io/CMakeLists.txt
+++ b/src/io/CMakeLists.txt
@@ -1,29 +1,41 @@
set(io_SRC
- base64stream.cpp
- bufferstream.cpp
- gzipstream.cpp
- inkscapestream.cpp
- resource.cpp
- stringstream.cpp
- sys.cpp
- http.cpp
- uristream.cpp
- xsltstream.cpp
+ base64stream.cpp
+ bufferstream.cpp
+ dir-util.cpp
+ gzipstream.cpp
+ inkscapestream.cpp
+ resource.cpp
+ resource-manager.cpp
+ stringstream.cpp
+ sys.cpp
+ http.cpp
+ uristream.cpp
+ xsltstream.cpp
- # -------
- # Headers
- base64stream.h
- bufferstream.h
- gzipstream.h
- inkscapestream.h
- resource.h
- stringstream.h
- sys.h
- http.h
- uristream.h
- xsltstream.h
+ # -------
+ # Headers
+ base64stream.h
+ bufferstream.h
+ dir-util.h
+ gzipstream.h
+ inkscapestream.h
+ resource.h
+ resource-manager.h
+ stringstream.h
+ sys.h
+ http.h
+ uristream.h
+ xsltstream.h
)
+if(WIN32)
+ # Sources for the inkscape executable on Windows.
+ list(APPEND io_SRC
+ registrytool.h
+ registrytool.cpp
+ )
+endif()
+
# add_inkscape_lib(io_LIB "${io_SRC}")
add_inkscape_source("${io_SRC}")
diff --git a/src/io/command_line_export.h b/src/io/command_line_export.h
new file mode 100644
index 000000000..dad0d573c
--- /dev/null
+++ b/src/io/command_line_export.h
@@ -0,0 +1,59 @@
+
+// Command line export... should be using normal export.
+
+
+class InkCommandLineExport {
+
+public:
+ enum {
+ EXPORT_PLAIN_SVG,
+ EXPORT_INKSCAPE_SVG,
+ EXPORT_PNG,
+ EXPORT_PS,
+ EXPORT_EPS,
+ EXPORT_PDF,
+ EXPORT_LATEX,
+ EXPORT_EMF,
+ EXPORT_WMF,
+ EXPORT_XAML,
+ EXPORT_PRINT
+ } ExportType;
+
+ InkCommandLineExport(ExportType export_type,
+ Glib::ustring file_name);
+ ~InkCommandLineExport() {};
+ do_export();
+
+ double export_dpi;
+ bool export_area;
+ bool export_area_drawing;
+ bool export_area_page;
+ double export_margin;
+ bool export_snap;
+ int export_width; // In pixels
+ int export_hight; // In pixels
+ Glib::ustring export_id;
+ bool export_id_only;
+ bool export_id_hints;
+ Glib::ustring export_background;
+ double export_background_opacity;
+ int export_ps_level;
+ double export_pdf_level;
+ bool export_text_to_path;
+ bool export_ignore_filters;
+
+private:
+ ExportType export_type;
+ Glib::ustring file_name;
+}
+
+/*
+ Local Variables:
+ mode:c++
+ c-file-style:"stroustrup"
+ c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
+ indent-tabs-mode:nil
+ fill-column:99
+ End:
+*/
+// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4 :
diff --git a/src/io/command_line_output.h b/src/io/command_line_output.h
new file mode 100644
index 000000000..31ce2cd47
--- /dev/null
+++ b/src/io/command_line_output.h
@@ -0,0 +1,58 @@
+
+// Command line export... should be using normal export.
+
+class InkCommandLineExport {
+
+public:
+ enum {
+ EXPORT_PLAIN_SVG,
+ EXPORT_INKSCAPE_SVG,
+ EXPORT_PNG,
+ EXPORT_PS,
+ EXPORT_EPS,
+ EXPORT_PDF,
+ EXPORT_LATEX,
+ EXPORT_EMF,
+ EXPORT_WMF,
+ EXPORT_XAML,
+ EXPORT_PRINT
+ } ExportType;
+
+ InkCommandLineExport(ExportType export_type,
+ Glib::ustring file_name);
+ ~InkCommandLineExport() {};
+ do_export();
+
+ double export_dpi;
+ bool export_area;
+ bool export_area_drawing;
+ bool export_area_page;
+ double export_margin;
+ bool export_snap;
+ int export_width; // In pixels
+ int export_hight; // In pixels
+ Glib::ustring export_id;
+ bool export_id_only;
+ bool export_id_hints;
+ Glib::ustring export_background;
+ double export_background_opacity;
+ int export_ps_level;
+ double export_pdf_level;
+ bool export_text_to_path;
+ bool export_ignore_filters;
+
+private:
+ ExportType export_type;
+ Glib::ustring file_name;
+}
+
+/*
+ Local Variables:
+ mode:c++
+ c-file-style:"stroustrup"
+ c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
+ indent-tabs-mode:nil
+ fill-column:99
+ End:
+*/
+// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4 :
diff --git a/src/io/commandline_io.h b/src/io/commandline_io.h
new file mode 100644
index 000000000..31ce2cd47
--- /dev/null
+++ b/src/io/commandline_io.h
@@ -0,0 +1,58 @@
+
+// Command line export... should be using normal export.
+
+class InkCommandLineExport {
+
+public:
+ enum {
+ EXPORT_PLAIN_SVG,
+ EXPORT_INKSCAPE_SVG,
+ EXPORT_PNG,
+ EXPORT_PS,
+ EXPORT_EPS,
+ EXPORT_PDF,
+ EXPORT_LATEX,
+ EXPORT_EMF,
+ EXPORT_WMF,
+ EXPORT_XAML,
+ EXPORT_PRINT
+ } ExportType;
+
+ InkCommandLineExport(ExportType export_type,
+ Glib::ustring file_name);
+ ~InkCommandLineExport() {};
+ do_export();
+
+ double export_dpi;
+ bool export_area;
+ bool export_area_drawing;
+ bool export_area_page;
+ double export_margin;
+ bool export_snap;
+ int export_width; // In pixels
+ int export_hight; // In pixels
+ Glib::ustring export_id;
+ bool export_id_only;
+ bool export_id_hints;
+ Glib::ustring export_background;
+ double export_background_opacity;
+ int export_ps_level;
+ double export_pdf_level;
+ bool export_text_to_path;
+ bool export_ignore_filters;
+
+private:
+ ExportType export_type;
+ Glib::ustring file_name;
+}
+
+/*
+ Local Variables:
+ mode:c++
+ c-file-style:"stroustrup"
+ c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
+ indent-tabs-mode:nil
+ fill-column:99
+ End:
+*/
+// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4 :
diff --git a/src/io/dir-util.cpp b/src/io/dir-util.cpp
new file mode 100644
index 000000000..1a215fa29
--- /dev/null
+++ b/src/io/dir-util.cpp
@@ -0,0 +1,254 @@
+/**
+ * @file
+ * Utility functions for filenames.
+ */
+
+#include <cerrno>
+#include <string>
+#include <cstring>
+#include <glib.h>
+#include "dir-util.h"
+
+std::string sp_relative_path_from_path( std::string const &path, std::string const &base)
+{
+ std::string result;
+ if ( !base.empty() && !path.empty() ) {
+ size_t base_len = base.length();
+ while (base_len != 0
+ && (base[base_len - 1] == G_DIR_SEPARATOR))
+ {
+ --base_len;
+ }
+
+ if ( (path.substr(0, base_len) == base.substr(0, base_len))
+ && (path[base_len] == G_DIR_SEPARATOR))
+ {
+ size_t retPos = base_len + 1;
+ while ( (retPos < path.length()) && (path[retPos] == G_DIR_SEPARATOR) ) {
+ retPos++;
+ }
+ if ( (retPos + 1) < path.length() ) {
+ result = path.substr(retPos);
+ }
+ }
+
+ }
+ if ( result.empty() ) {
+ result = path;
+ }
+ return result;
+}
+
+char const *sp_extension_from_path(char const *const path)
+{
+ if (path == nullptr) {
+ return nullptr;
+ }
+
+ char const *p = path;
+ while (*p != '\0') p++;
+
+ while ((p >= path) && (*p != G_DIR_SEPARATOR) && (*p != '.')) p--;
+ if (* p != '.') return nullptr;
+ p++;
+
+ return p;
+}
+
+
+/* current == "./", parent == "../" */
+static char const dots[] = {'.', '.', G_DIR_SEPARATOR, '\0'};
+static char const *const parent = dots;
+static char const *const current = dots + 1;
+
+char *inkscape_rel2abs(const char *path, const char *base, char *result, const size_t size)
+{
+ const char *pp, *bp;
+ /* endp points the last position which is safe in the result buffer. */
+ const char *endp = result + size - 1;
+ char *rp;
+ int length;
+ if (*path == G_DIR_SEPARATOR)
+ {
+ if (strlen (path) >= size)
+ goto erange;
+ strcpy (result, path);
+ goto finish;
+ }
+ else if (*base != G_DIR_SEPARATOR || !size)
+ {
+ errno = EINVAL;
+ return (nullptr);
+ }
+ else if (size == 1)
+ goto erange;
+ if (!strcmp (path, ".") || !strcmp (path, current))
+ {
+ if (strlen (base) >= size)
+ goto erange;
+ strcpy (result, base);
+ /* rp points the last char. */
+ rp = result + strlen (base) - 1;
+ if (*rp == G_DIR_SEPARATOR)
+ *rp = 0;
+ else
+ rp++;
+ /* rp point NULL char */
+ if (*++path == G_DIR_SEPARATOR)
+ {
+ /* Append G_DIR_SEPARATOR to the tail of path name. */
+ *rp++ = G_DIR_SEPARATOR;
+ if (rp > endp)
+ goto erange;
+ *rp = 0;
+ }
+ goto finish;
+ }
+ bp = base + strlen (base);
+ if (*(bp - 1) == G_DIR_SEPARATOR)
+ --bp;
+ /* up to root. */
+ for (pp = path; *pp && *pp == '.';)
+ {
+ if (!strncmp (pp, parent, 3))
+ {
+ pp += 3;
+ while (bp > base && *--bp != G_DIR_SEPARATOR)
+ ;
+ }
+ else if (!strncmp (pp, current, 2))
+ {
+ pp += 2;
+ }
+ else if (!strncmp (pp, "..\0", 3))
+ {
+ pp += 2;
+ while (bp > base && *--bp != G_DIR_SEPARATOR)
+ ;
+ }
+ else
+ break;
+ }
+ /* down to leaf. */
+ length = bp - base;
+ if (length >= static_cast<int>(size))
+ goto erange;
+ strncpy (result, base, length);
+ rp = result + length;
+ if (*pp || *(pp - 1) == G_DIR_SEPARATOR || length == 0)
+ *rp++ = G_DIR_SEPARATOR;
+ if (rp + strlen (pp) > endp)
+ goto erange;
+ strcpy (rp, pp);
+finish:
+ return result;
+erange:
+ errno = ERANGE;
+ return (nullptr);
+}
+
+char *inkscape_abs2rel(const char *path, const char *base, char *result, const size_t size)
+{
+ const char *pp, *bp, *branch;
+ // endp points the last position which is safe in the result buffer.
+ const char *endp = result + size - 1;
+ char *rp;
+
+ if (*path != G_DIR_SEPARATOR)
+ {
+ if (strlen (path) >= size)
+ goto erange;
+ strcpy (result, path);
+ goto finish;
+ }
+ else if (*base != G_DIR_SEPARATOR || !size)
+ {
+ errno = EINVAL;
+ return (nullptr);
+ }
+ else if (size == 1)
+ goto erange;
+ /* seek to branched point. */
+ branch = path;
+ for (pp = path, bp = base; *pp && *bp && *pp == *bp; pp++, bp++)
+ if (*pp == G_DIR_SEPARATOR)
+ branch = pp;
+ if (((*pp == 0) || ((*pp == G_DIR_SEPARATOR) && (*(pp + 1) == 0))) &&
+ ((*bp == 0) || ((*bp == G_DIR_SEPARATOR) && (*(bp + 1) == 0))))
+ {
+ rp = result;
+ *rp++ = '.';
+ if (*pp == G_DIR_SEPARATOR || *(pp - 1) == G_DIR_SEPARATOR)
+ *rp++ = G_DIR_SEPARATOR;
+ if (rp > endp)
+ goto erange;
+ *rp = 0;
+ goto finish;
+ }
+ if (((*pp == 0) && (*bp == G_DIR_SEPARATOR)) || ((*pp == G_DIR_SEPARATOR) && (*bp == 0)))
+ branch = pp;
+ /* up to root. */
+ rp = result;
+ for (bp = base + (branch - path); *bp; bp++)
+ if (*bp == G_DIR_SEPARATOR && *(bp + 1) != 0)
+ {
+ if (rp + 3 > endp)
+ goto erange;
+ *rp++ = '.';
+ *rp++ = '.';
+ *rp++ = G_DIR_SEPARATOR;
+ }
+ if (rp > endp)
+ goto erange;
+ *rp = 0;
+ /* down to leaf. */
+ if (*branch)
+ {
+ if (rp + strlen (branch + 1) > endp)
+ goto erange;
+ strcpy (rp, branch + 1);
+ }
+ else
+ *--rp = 0;
+finish:
+ return result;
+erange:
+ errno = ERANGE;
+ return (nullptr);
+}
+
+char *prepend_current_dir_if_relative(gchar const *uri)
+{
+ if (!uri) {
+ return nullptr;
+ }
+
+ gchar *full_path = (gchar *) g_malloc (1001);
+ gchar *cwd = g_get_current_dir();
+
+ gsize bytesRead = 0;
+ gsize bytesWritten = 0;
+ GError* error = nullptr;
+ gchar* cwd_utf8 = g_filename_to_utf8 ( cwd,
+ -1,
+ &bytesRead,
+ &bytesWritten,
+ &error);
+
+ inkscape_rel2abs (uri, cwd_utf8, full_path, 1000);
+ gchar *ret = g_strdup (full_path);
+ g_free (full_path);
+ g_free (cwd);
+ return ret;
+}
+
+/*
+ Local Variables:
+ mode:c++
+ c-file-style:"stroustrup"
+ c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
+ indent-tabs-mode:nil
+ fill-column:99
+ End:
+*/
+// vi: set autoindent shiftwidth=4 tabstop=8 filetype=cpp expandtab softtabstop=4 encoding=utf-8 textwidth=99 :
diff --git a/src/io/dir-util.h b/src/io/dir-util.h
new file mode 100644
index 000000000..327e1ad5f
--- /dev/null
+++ b/src/io/dir-util.h
@@ -0,0 +1,66 @@
+#ifndef SEEN_DIR_UTIL_H
+#define SEEN_DIR_UTIL_H
+
+/*
+ * path-util.h
+ *
+ * here are functions sp_relative_path & cousins
+ * maybe they are already implemented in standard libs
+ *
+ */
+
+#include <cstdlib>
+#include <string>
+
+/**
+ * Returns a form of \a path relative to \a base if that is easy to construct (eg if \a path
+ * appears to be in the directory specified by \a base), otherwise returns \a path.
+ *
+ * @param path is expected to be an absolute path.
+ * @param base is expected to be either empty or the absolute path of a directory.
+ *
+ * @return a relative version of the path, if reasonable.
+ *
+ * @see inkscape_abs2rel for a more sophisticated version.
+ * @see prepend_current_dir_if_relative.
+*/
+std::string sp_relative_path_from_path(std::string const &path, std::string const &base);
+
+char const *sp_extension_from_path(char const *path);
+
+/**
+ * Convert a relative path name into absolute. If path is already absolute, does nothing except copying path to result.
+ *
+ * @param path relative path.
+ * @param base base directory (must be absolute path).
+ * @param result result buffer.
+ * @param size size of result buffer.
+ *
+ * @return != NULL: absolute path
+ * == NULL: error
+ *
+ * based on functions by Shigio Yamaguchi.
+ * FIXME:TODO: force it to also do path normalization of the entire resulting path,
+ * i.e. get rid of any .. and . in any place, even if 'path' is already absolute
+ * (now it returns it unchanged in this case)
+ *
+ */
+char *inkscape_rel2abs(char const *path, char const *base, char *result, size_t const size);
+
+char *inkscape_abs2rel(char const *path, char const *base, char *result, size_t const size);
+
+char *prepend_current_dir_if_relative(char const *filename);
+
+
+#endif // !SEEN_DIR_UTIL_H
+
+/*
+ Local Variables:
+ mode:c++
+ c-file-style:"stroustrup"
+ c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
+ indent-tabs-mode:nil
+ fill-column:99
+ End:
+*/
+// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:fileencoding=utf-8:textwidth=99 :
diff --git a/src/io/file.h b/src/io/file.h
new file mode 100644
index 000000000..c0c44f6ab
--- /dev/null
+++ b/src/io/file.h
@@ -0,0 +1,25 @@
+/*
+ * File operations (independent of GUI)
+ *
+ * Copyright (C) 2018 Tavmjong Bah
+ *
+ * The contents of this file may be used under the GNU General Public License Version 2 or later.
+ *
+ */
+
+#ifndef INK_FILE_IO_H
+#define INK_FILE_IO_H
+
+class SPDocument;
+
+SPDocument* ink_file_new(const std::string &template = nullptr);
+SPDocument* ink_file_open(const Glib::RefPtr<Gio::File>& file = Glib::RefPtr<Gio::File>());
+
+// To do:
+// ink_file_save()
+// ink_file_export()
+// ink_file_import()
+
+
+
+#endif // INK_FILE_IO_H
diff --git a/src/io/open_file.h b/src/io/open_file.h
new file mode 100644
index 000000000..5da25f88e
--- /dev/null
+++ b/src/io/open_file.h
@@ -0,0 +1,12 @@
+/*
+ * File operations (independent of GUI)
+ *
+ * Copyright (C) 2018 Tavmjong Bah
+ *
+ * The contents of this file may be used under the GNU General Public License Version 2 or later.
+ *
+ */
+
+SPDocument* open_file(const Glib::RefPtr<Gio::File>& file = Glib::RefPtr<Gio::File>());
+
+
diff --git a/src/io/registrytool.cpp b/src/io/registrytool.cpp
new file mode 100644
index 000000000..89442bc36
--- /dev/null
+++ b/src/io/registrytool.cpp
@@ -0,0 +1,226 @@
+/*
+ * Inkscape Registry Tool
+ *
+ * Authors:
+ * Bob Jamison
+ *
+ * Copyright (C) 2005-2008 Bob Jamison
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include "registrytool.h"
+
+#include <windows.h>
+#include <string>
+#include <cstdio>
+
+#include <glibmm/ustring.h>
+
+struct KeyTableEntry
+{
+ HKEY key;
+ int strlen;
+ const char *str;
+};
+
+
+
+KeyTableEntry keyTable[] =
+{
+ { HKEY_CLASSES_ROOT, 18, "HKEY_CLASSES_ROOT\\" },
+ { HKEY_CURRENT_CONFIG, 20, "HKEY_CURRENT_CONFIG\\" },
+ { HKEY_CURRENT_USER, 18, "HKEY_CURRENT_USER\\" },
+ { HKEY_LOCAL_MACHINE, 19, "HKEY_LOCAL_MACHINE\\" },
+ { HKEY_USERS, 11, "HKEY_USERS\\" },
+ { NULL, 0, NULL }
+};
+
+
+bool RegistryTool::setStringValue(const Glib::ustring &keyNameArg,
+ const Glib::ustring &valueName,
+ const Glib::ustring &value)
+{
+ Glib::ustring keyName = keyNameArg;
+ bool ret = false;
+
+ HKEY rootKey = HKEY_LOCAL_MACHINE; //default root
+ //Trim out the root key if necessary
+ for (KeyTableEntry *entry = keyTable; entry->key; entry++)
+ {
+ if (keyName.compare(0, entry->strlen, entry->str)==0)
+ {
+ rootKey = entry->key;
+ keyName = keyName.substr(entry->strlen);
+ }
+ }
+ //printf("trimmed string: '%s'\n", keyName.c_str());
+
+ //Get or create the key
+ gunichar2 *keyw = g_utf8_to_utf16(keyName.data(), -1, 0,0,0);
+ gunichar2 *valuenamew = g_utf8_to_utf16(valueName.data(), -1, 0,0,0);
+ gunichar2 *valuew = g_utf8_to_utf16(value.data(), -1, 0,0,0);
+
+ HKEY key;
+ if (RegCreateKeyExW(rootKey, (WCHAR*) keyw,
+ 0, NULL, REG_OPTION_NON_VOLATILE,
+ KEY_WRITE, NULL, &key, NULL))
+ {
+ fprintf(stderr, "RegistryTool: Could not create the registry key '%s'\n", keyName.c_str());
+ goto fail;
+ }
+
+ // Set the value
+ if (RegSetValueExW(key, (WCHAR*) valuenamew,
+ 0, REG_SZ, (LPBYTE) valuew, (DWORD) (2*value.size() + 2)))
+ {
+ fprintf(stderr, "RegistryTool: Could not set the value '%s'\n", value.c_str());
+ goto failkey;
+ }
+
+ ret = true;
+
+ failkey:
+ RegCloseKey(key);
+
+ fail:
+ g_free(keyw);
+ g_free(valuenamew);
+ return ret;
+}
+
+
+
+bool RegistryTool::getExeInfo(Glib::ustring &fullPath,
+ Glib::ustring &path,
+ Glib::ustring &exeName)
+{
+ const int pathbuf = 2048;
+ gunichar2 pathw[pathbuf];
+ GetModuleFileNameW(NULL, (WCHAR*) pathw, pathbuf);
+
+ gchar *utf8path = g_utf16_to_utf8(pathw, -1, 0,0,0);
+ fullPath = utf8path;
+ g_free(utf8path);
+
+ path = "";
+ exeName = "";
+ Glib::ustring::size_type pos = fullPath.rfind('\\');
+ if (pos != fullPath.npos)
+ {
+ path = fullPath.substr(0, pos);
+ exeName = fullPath.substr(pos+1);
+ }
+
+ return true;
+}
+
+
+
+bool RegistryTool::setPathInfo()
+{
+ Glib::ustring fullPath;
+ Glib::ustring path;
+ Glib::ustring exeName;
+
+ if (!getExeInfo(fullPath, path, exeName))
+ return false;
+
+ //printf("full:'%s' path:'%s' exe:'%s'\n",
+ // fullPath.c_str(), path.c_str(), exeName.c_str());
+
+ Glib::ustring keyName =
+ "HKEY_CURRENT_USER\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\App Paths\\";
+ keyName.append(exeName);
+
+ Glib::ustring valueName = "";
+ Glib::ustring value = fullPath;
+
+ if (!setStringValue(keyName, valueName, value))
+ return false;
+
+ //add our subdirectories
+ Glib::ustring appPath = path;
+ appPath.append("\\python;");
+ appPath.append(path);
+ appPath.append("\\perl");
+ valueName = "Path";
+ value = appPath;
+
+ if (!setStringValue(keyName, valueName, value))
+ return false;
+
+ return true;
+}
+
+
+#ifdef TESTREG
+
+
+/*
+ * Compile this file with
+ * g++ -DTESTREG registrytool.cpp -o registrytool
+ * to run these tests.
+ */
+
+
+
+void testReg()
+{
+ RegistryTool rt;
+ char *key =
+ "HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\App Paths\\inkscape.exe";
+ char const *name = "";
+ char const *value = "c:\\inkscape\\inkscape.exe";
+ if (!rt.setStringValue(key, name, value))
+ {
+ printf("Test failed\n");
+ }
+ else
+ {
+ printf("Test succeeded\n");
+ }
+ name = "Path";
+ value = "c:\\inkscape\\python";
+ if (!rt.setStringValue(key, name, value))
+ {
+ printf("Test failed\n");
+ }
+ else
+ {
+ printf("Test succeeded\n");
+ }
+}
+
+
+void testPath()
+{
+ RegistryTool rt;
+ rt.setPathInfo();
+}
+
+
+int main(int argc, char **argv)
+{
+ //testReg();
+ testPath();
+ return 0;
+}
+
+#endif /* TESTREG */
+
+//########################################################################
+//# E N D O F F I L E
+//########################################################################
diff --git a/src/io/registrytool.h b/src/io/registrytool.h
new file mode 100644
index 000000000..335a8bd52
--- /dev/null
+++ b/src/io/registrytool.h
@@ -0,0 +1,69 @@
+#ifndef SEEN_REGISTRYTOOL_H
+#define SEEN_REGISTRYTOOL_H
+/*
+ * Authors:
+ * Bob Jamison
+ *
+ * Copyright (C) 2005 Bob Jamison
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+namespace Glib {
+ class ustring;
+}
+
+/**
+ * Inkscape Registry Tool
+ *
+ * This simple tool is intended for allowing Inkscape to append subdirectories
+ * to its path. This will allow extensions and other files to be accesses
+ * without explicit user intervention.
+ */
+class RegistryTool
+{
+public:
+
+ RegistryTool()
+ {}
+
+ virtual ~RegistryTool()
+ {}
+
+ /**
+ * Set the string value of a key/name registry entry.
+ */
+ bool setStringValue(const Glib::ustring &key,
+ const Glib::ustring &valueName,
+ const Glib::ustring &value);
+
+ /**
+ * Get the full path, directory, and base file name of this running executable.
+ */
+ bool getExeInfo(Glib::ustring &fullPath,
+ Glib::ustring &path,
+ Glib::ustring &exeName);
+
+ /**
+ * Append our subdirectories to the Application Path for this
+ * application.
+ */
+ bool setPathInfo();
+
+
+};
+
+#endif // SEEN_REGISTRYTOOL_H
+
diff --git a/src/io/resource-manager.cpp b/src/io/resource-manager.cpp
new file mode 100644
index 000000000..6a455a8cc
--- /dev/null
+++ b/src/io/resource-manager.cpp
@@ -0,0 +1,445 @@
+/*
+ * Inkscape::ResourceManager - tracks external resources such as image and css files.
+ *
+ * Copyright 2011 Jon A. Cruz <jon@joncruz.org>
+ *
+ * Released under GNU GPL, read the file 'COPYING' for more information
+ */
+
+#include <string>
+#include <vector>
+#include <algorithm>
+
+#include <gtkmm/recentmanager.h>
+#include <glibmm/i18n.h>
+#include <glibmm/miscutils.h>
+#include <glibmm/fileutils.h>
+#include <glibmm/uriutils.h>
+#include <glibmm/convert.h>
+
+#include "resource-manager.h"
+
+#include "document.h"
+#include "document-undo.h"
+#include "verbs.h"
+
+#include "object/sp-object.h"
+
+#include "xml/node.h"
+
+namespace Inkscape {
+
+static std::vector<std::string> splitPath( std::string const &path )
+{
+ std::vector<std::string> parts;
+
+ std::string prior;
+ std::string tmp = path;
+ while ( !tmp.empty() && (tmp != prior) ) {
+ prior = tmp;
+
+ parts.push_back( Glib::path_get_basename(tmp) );
+ tmp = Glib::path_get_dirname(tmp);
+ }
+ if ( !parts.empty() ) {
+ std::reverse(parts.begin(), parts.end());
+ if ( (parts[0] == ".") && (path[0] != '.') ) {
+ parts.erase(parts.begin());
+ }
+ }
+
+ return parts;
+}
+
+static std::string convertPathToRelative( std::string const &path, std::string const &docbase )
+{
+ std::string result = path;
+
+ if ( !path.empty() && Glib::path_is_absolute(path) ) {
+ // Whack the parts into pieces
+
+ std::vector<std::string> parts = splitPath(path);
+ std::vector<std::string> baseParts = splitPath(docbase);
+
+ // TODO debug g_message("+++++++++++++++++++++++++");
+ for ( std::vector<std::string>::iterator it = parts.begin(); it != parts.end(); ++it ) {
+ // TODO debug g_message(" [%s]", it->c_str());
+ }
+ // TODO debug g_message(" - - - - - - - - - - - - - - - ");
+ for ( std::vector<std::string>::iterator it = baseParts.begin(); it != baseParts.end(); ++it ) {
+ // TODO debug g_message(" [%s]", it->c_str());
+ }
+ // TODO debug g_message("+++++++++++++++++++++++++");
+
+ if ( !parts.empty() && !baseParts.empty() && (parts[0] == baseParts[0]) ) {
+ // Both paths have the same root. We can proceed.
+ while ( !parts.empty() && !baseParts.empty() && (parts[0] == baseParts[0]) ) {
+ parts.erase( parts.begin() );
+ baseParts.erase( baseParts.begin() );
+ }
+
+ // TODO debug g_message("+++++++++++++++++++++++++");
+ for ( std::vector<std::string>::iterator it = parts.begin(); it != parts.end(); ++it ) {
+ // TODO debug g_message(" [%s]", it->c_str());
+ }
+ // TODO debug g_message(" - - - - - - - - - - - - - - - ");
+ for ( std::vector<std::string>::iterator it = baseParts.begin(); it != baseParts.end(); ++it ) {
+ // TODO debug g_message(" [%s]", it->c_str());
+ }
+ // TODO debug g_message("+++++++++++++++++++++++++");
+
+ if ( !parts.empty() ) {
+ result.clear();
+
+ for ( size_t i = 0; i < baseParts.size(); ++i ) {
+ parts.insert(parts.begin(), "..");
+ }
+ result = Glib::build_filename( parts );
+ // TODO debug g_message("----> [%s]", result.c_str());
+ }
+ }
+ }
+
+ return result;
+}
+
+
+class ResourceManagerImpl : public ResourceManager {
+public:
+ ResourceManagerImpl();
+ ~ResourceManagerImpl() override;
+
+ bool fixupBrokenLinks(SPDocument *doc) override;
+
+
+ /**
+ * Walk all links in a document and create a listing of unique broken links.
+ *
+ * @return a list of all broken links.
+ */
+ std::vector<Glib::ustring> findBrokenLinks(SPDocument *doc);
+
+ /**
+ * Resolve broken links as a whole and return a map for those that can be found.
+ *
+ * Note: this will allow for future enhancements including relinking to new locations
+ * with the most broken files found, etc.
+ *
+ * @return a map of found links.
+ */
+ std::map<Glib::ustring, Glib::ustring> locateLinks(Glib::ustring const & docbase, std::vector<Glib::ustring> const & brokenLinks);
+
+
+ /**
+ * Try to parse href into a local filename using standard methods.
+ *
+ * @return true if successful.
+ */
+ bool extractFilepath( Glib::ustring const &href, std::string &uri );
+
+ /**
+ * Try to parse href into a local filename using some non-standard methods.
+ * This means the href is likely invalid and should be rewritten.
+ *
+ * @return true if successful.
+ */
+ bool reconstructFilepath( Glib::ustring const &href, std::string &uri );
+
+ bool searchUpwards( std::string const &base, std::string const &subpath, std::string &dest );
+
+protected:
+};
+
+
+ResourceManagerImpl::ResourceManagerImpl()
+ : ResourceManager()
+{
+}
+
+ResourceManagerImpl::~ResourceManagerImpl()
+= default;
+
+bool ResourceManagerImpl::extractFilepath( Glib::ustring const &href, std::string &uri )
+{
+ bool isFile = false;
+
+ uri.clear();
+
+ std::string scheme = Glib::uri_parse_scheme(href);
+ if ( !scheme.empty() ) {
+ // TODO debug g_message("Scheme is now [%s]", scheme.c_str());
+ if ( scheme == "file" ) {
+ // TODO debug g_message("--- is a file URI [%s]", href.c_str());
+
+ // throws Glib::ConvertError:
+ try {
+ uri = Glib::filename_from_uri(href);
+ // TODO debug g_message(" [%s]", uri.c_str());
+ isFile = true;
+ } catch(Glib::ConvertError e) {
+ g_warning("%s", e.what().c_str());
+ }
+ }
+ } else {
+ // No scheme. Assuming it is a file path (absolute or relative).
+ // throws Glib::ConvertError:
+ uri = Glib::filename_from_utf8( href );
+ isFile = true;
+ }
+
+ return isFile;
+}
+
+bool ResourceManagerImpl::reconstructFilepath( Glib::ustring const &href, std::string &uri )
+{
+ bool isFile = false;
+
+ uri.clear();
+
+ std::string scheme = Glib::uri_parse_scheme(href);
+ if ( !scheme.empty() ) {
+ if ( scheme == "file" ) {
+ // try to build a relative filename for URIs like "file:image.png"
+ // they're not standard conformant but not uncommon
+ Glib::ustring href_new = Glib::ustring(href, 5);
+ uri = Glib::filename_from_utf8(href_new);
+ // TODO debug g_message("reconstructed path for '%s' into '%s'", href.c_str(), uri.c_str());
+ isFile = true;
+ }
+ }
+ return isFile;
+}
+
+
+std::vector<Glib::ustring> ResourceManagerImpl::findBrokenLinks( SPDocument *doc )
+{
+ std::vector<Glib::ustring> result;
+ std::set<Glib::ustring> uniques;
+
+ if ( doc ) {
+ std::vector<SPObject *> images = doc->getResourceList("image");
+ for (std::vector<SPObject *>::const_iterator it = images.begin(); it != images.end(); ++it) {
+ Inkscape::XML::Node *ir = (*it)->getRepr();
+
+ gchar const *href = ir->attribute("xlink:href");
+ if ( href && ( uniques.find(href) == uniques.end() ) ) {
+ std::string uri;
+ if ( extractFilepath( href, uri ) ) {
+ if ( Glib::path_is_absolute(uri) ) {
+ if ( !Glib::file_test(uri, Glib::FILE_TEST_EXISTS) ) {
+ result.emplace_back(href);
+ uniques.insert(href);
+ }
+ } else {
+ std::string combined = Glib::build_filename(doc->getBase(), uri);
+ if ( !Glib::file_test(combined, Glib::FILE_TEST_EXISTS) ) {
+ result.emplace_back(href);
+ uniques.insert(href);
+ }
+ }
+ } else if ( reconstructFilepath( href, uri ) ) {
+ result.emplace_back(href);
+ uniques.insert(href);
+ }
+ }
+ }
+ }
+
+ return result;
+}
+
+
+std::map<Glib::ustring, Glib::ustring> ResourceManagerImpl::locateLinks(Glib::ustring const & docbase, std::vector<Glib::ustring> const & brokenLinks)
+{
+ std::map<Glib::ustring, Glib::ustring> result;
+
+
+ // Note: we use a vector because we want them to stay in order:
+ std::vector<std::string> priorLocations;
+
+ Glib::RefPtr<Gtk::RecentManager> recentMgr = Gtk::RecentManager::get_default();
+ std::vector< Glib::RefPtr<Gtk::RecentInfo> > recentItems = recentMgr->get_items();
+ for ( std::vector< Glib::RefPtr<Gtk::RecentInfo> >::iterator it = recentItems.begin(); it != recentItems.end(); ++it ) {
+ Glib::ustring uri = (*it)->get_uri();
+ std::string scheme = Glib::uri_parse_scheme(uri);
+ if ( scheme == "file" ) {
+ try {
+ std::string path = Glib::filename_from_uri(uri);
+ path = Glib::path_get_dirname(path);
+ if ( std::find(priorLocations.begin(), priorLocations.end(), path) == priorLocations.end() ) {
+ // TODO debug g_message(" ==>[%s]", path.c_str());
+ priorLocations.push_back(path);
+ }
+ } catch (Glib::ConvertError e) {
+ g_warning("%s", e.what().c_str());
+ }
+ }
+ }
+
+ // At the moment we expect this list to contain file:// references, or simple relative or absolute paths.
+ for ( std::vector<Glib::ustring>::const_iterator it = brokenLinks.begin(); it != brokenLinks.end(); ++it ) {
+ // TODO debug g_message("========{%s}", it->c_str());
+
+ std::string uri;
+ if ( extractFilepath( *it, uri ) || reconstructFilepath( *it, uri ) ) {
+ // We were able to get some path. Check it
+ std::string origPath = uri;
+
+ if ( !Glib::path_is_absolute(uri) ) {
+ uri = Glib::build_filename(docbase, uri);
+ // TODO debug g_message(" not absolute. Fixing up as [%s]", uri.c_str());
+ }
+
+ bool exists = Glib::file_test(uri, Glib::FILE_TEST_EXISTS);
+
+ // search in parent folders
+ if (!exists) {
+ exists = searchUpwards( docbase, origPath, uri );
+ }
+
+ // Check if the MRU bases point us to it.
+ if ( !exists ) {
+ if ( !Glib::path_is_absolute(origPath) ) {
+ for ( std::vector<std::string>::iterator it = priorLocations.begin(); !exists && (it != priorLocations.end()); ++it ) {
+ exists = searchUpwards( *it, origPath, uri );
+ }
+ }
+ }
+
+ if ( exists ) {
+ if ( Glib::path_is_absolute( uri ) ) {
+ // TODO debug g_message("Need to convert to relative if possible [%s]", uri.c_str());
+ uri = convertPathToRelative( uri, docbase );
+ }
+
+ bool isAbsolute = Glib::path_is_absolute( uri );
+ Glib::ustring replacement = isAbsolute ? Glib::filename_to_uri( uri ) : Glib::filename_to_utf8( uri );
+ result[*it] = replacement;
+ }
+ }
+ }
+
+ return result;
+}
+
+bool ResourceManagerImpl::fixupBrokenLinks(SPDocument *doc)
+{
+ bool changed = false;
+ if ( doc ) {
+ // TODO debug g_message("FIXUP FIXUP FIXUP FIXUP FIXUP FIXUP FIXUP FIXUP FIXUP FIXUP");
+ // TODO debug g_message(" base is [%s]", doc->getBase());
+
+ std::vector<Glib::ustring> brokenHrefs = findBrokenLinks(doc);
+ if ( !brokenHrefs.empty() ) {
+ // TODO debug g_message(" FOUND SOME LINKS %d", static_cast<int>(brokenHrefs.size()));
+ for ( std::vector<Glib::ustring>::iterator it = brokenHrefs.begin(); it != brokenHrefs.end(); ++it ) {
+ // TODO debug g_message(" [%s]", it->c_str());
+ }
+ }
+
+ std::map<Glib::ustring, Glib::ustring> mapping = locateLinks(doc->getBase(), brokenHrefs);
+ for ( std::map<Glib::ustring, Glib::ustring>::iterator it = mapping.begin(); it != mapping.end(); ++it )
+ {
+ // TODO debug g_message(" [%s] ==> {%s}", it->first.c_str(), it->second.c_str());
+ }
+
+ bool savedUndoState = DocumentUndo::getUndoSensitive(doc);
+ DocumentUndo::setUndoSensitive(doc, true);
+
+ std::vector<SPObject *> images = doc->getResourceList("image");
+ for (std::vector<SPObject *>::const_iterator it = images.begin(); it != images.end(); ++it) {
+ Inkscape::XML::Node *ir = (*it)->getRepr();
+
+ gchar const *href = ir->attribute("xlink:href");
+ if ( href ) {
+ // TODO debug g_message(" consider [%s]", href);
+
+ if ( mapping.find(href) != mapping.end() ) {
+ // TODO debug g_message(" Found a replacement");
+
+ ir->setAttribute( "xlink:href", mapping[href].c_str() );
+ if ( ir->attribute( "sodipodi:absref" ) ) {
+ ir->setAttribute( "sodipodi:absref", nullptr ); // Remove this attribute
+ }
+
+ SPObject *updated = doc->getObjectByRepr(ir);
+ if (updated) {
+ // force immediate update of dependent attributes
+ updated->updateRepr();
+ }
+
+ changed = true;
+ }
+ }
+ }
+ if ( changed ) {
+ DocumentUndo::done( doc, SP_VERB_DIALOG_XML_EDITOR, _("Fixup broken links") );
+ }
+ DocumentUndo::setUndoSensitive(doc, savedUndoState);
+ }
+
+ return changed;
+}
+
+
+bool ResourceManagerImpl::searchUpwards( std::string const &base, std::string const &subpath, std::string &dest )
+{
+ bool exists = false;
+ // TODO debug g_message("............");
+
+ std::vector<std::string> parts = splitPath(subpath);
+ std::vector<std::string> baseParts = splitPath(base);
+
+ while ( !exists && !baseParts.empty() ) {
+ std::vector<std::string> current;
+ current.insert(current.begin(), parts.begin(), parts.end());
+ // TODO debug g_message(" ---{%s}", Glib::build_filename( baseParts ).c_str());
+ while ( !exists && !current.empty() ) {
+ std::vector<std::string> combined;
+ combined.insert( combined.end(), baseParts.begin(), baseParts.end() );
+ combined.insert( combined.end(), current.begin(), current.end() );
+ std::string filepath = Glib::build_filename( combined );
+ exists = Glib::file_test(filepath, Glib::FILE_TEST_EXISTS);
+ // TODO debug g_message(" ...[%s] %s", filepath.c_str(), (exists ? "XXX" : ""));
+ if ( exists ) {
+ dest = filepath;
+ }
+ current.erase( current.begin() );
+ }
+ baseParts.pop_back();
+ }
+
+ return exists;
+}
+
+
+static ResourceManagerImpl* theInstance = nullptr;
+
+ResourceManager::ResourceManager()
+ : Glib::Object()
+{
+}
+
+ResourceManager::~ResourceManager() = default;
+
+ResourceManager& ResourceManager::getManager() {
+ if ( !theInstance ) {
+ theInstance = new ResourceManagerImpl();
+ }
+
+ return *theInstance;
+}
+
+
+} // namespace Inkscape
+
+/*
+ Local Variables:
+ mode:c++
+ c-file-style:"stroustrup"
+ c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
+ indent-tabs-mode:nil
+ fill-column:99
+ End:
+*/
+// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4 :
diff --git a/src/io/resource-manager.h b/src/io/resource-manager.h
new file mode 100644
index 000000000..b4d88c7e6
--- /dev/null
+++ b/src/io/resource-manager.h
@@ -0,0 +1,49 @@
+/*
+ * Inkscape::ResourceManager - Manages external resources such as image and css files.
+ *
+ * Copyright 2011 Jon A. Cruz <jon@joncruz.org>
+ *
+ * Released under GNU GPL, read the file 'COPYING' for more information
+ */
+
+#ifndef SEEN_INKSCAPE_RESOURCE_MANAGER_H
+#define SEEN_INKSCAPE_RESOURCE_MANAGER_H
+
+#include <glibmm/object.h>
+
+class SPDocument;
+
+namespace Inkscape {
+
+class ResourceManager : public Glib::Object {
+
+public:
+ static ResourceManager& getManager();
+
+ virtual bool fixupBrokenLinks(SPDocument *doc) = 0;
+
+protected:
+ ResourceManager();
+ ~ResourceManager() override;
+
+private:
+ ResourceManager(ResourceManager const &) = delete; // no copy
+ void operator=(ResourceManager const &) = delete; // no assign
+};
+
+
+
+} // namespace Inkscape
+
+#endif // SEEN_INKSCAPE_RESOURCE_MANAGER_H
+
+/*
+ Local Variables:
+ mode:c++
+ c-file-style:"stroustrup"
+ c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
+ indent-tabs-mode:nil
+ fill-column:99
+ End:
+*/
+// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:fileencoding=utf-8:textwidth=99 :