1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
package Torello.HTML;

import Torello.Java.StringParse;
import Torello.Java.StrCmpr;

import Torello.Java.Additional.Ret2;

import java.net.URL;
import java.net.MalformedURLException;

class LinksResolve_KE
{
    static Ret2<URL, MalformedURLException> resolve(String src, final URL sourcePage)
    {
        if (sourcePage == null) throw new NullPointerException(
            "Though you may provide null to the partial-URL to dereference parameter, null " +
            "may not be passed to the Source-Page Parameter.  The purpose of the 'resolve' " +
            "operation is to resolve partial-URLs against a source-page (root) URL. " +
            "Therefore this is not allowed."
        );

        if (src == null) return null;

        src = src.trim();

        if (src.length() == 0) return null;

        String srcLC = src.toLowerCase();

        if (StrCmpr.startsWithXOR
                (srcLC, "tel:", "javascript:", "mailto:", "magnet:", "file:", "ftp:", "#"))

            return new Ret2<URL, MalformedURLException>
                (null, new MalformedURLException(
                    "InnerTag/Attribute begins with: " + src.substring(0, 1 + src.indexOf(":")) +
                    ", so it is not a hyper-link."
                ));


        // Includes the first few characters of the URL - for reporting/convenience. 
        // If this is an "image", the image-type & name will be included

        if (StrCmpr.startsWithXOR(srcLC, "data:", "blob:"))

            return new Ret2<URL, MalformedURLException>(null, new MalformedURLException(
                "InnerTag/Attribute begins with: " +
                ((src.length() > 25) ? src.substring(0, 25) : src) +
                ", not a URL."
            ));


        if (srcLC.startsWith("http://") || srcLC.startsWith("https://"))

            try
                { return new Ret2<URL, MalformedURLException>(new URL(src), null); }

            catch (MalformedURLException e)
                { return new Ret2<URL, MalformedURLException>(null, e); }


        if (src.startsWith("//") && (src.charAt(3) != '/'))

            try
            { 
                return new Ret2<URL, MalformedURLException>
                    (new URL(  sourcePage.getProtocol().toLowerCase() + ":" + src), null);
            }

            catch (MalformedURLException e)
                { return new Ret2<URL, MalformedURLException>(null, e); }


        if (src.startsWith("/"))

            try
            {
                return new Ret2<URL, MalformedURLException>(new URL(
                    sourcePage.getProtocol().toLowerCase() + "://" +
                    sourcePage.getHost().toLowerCase() +
                    src), null
                );
            }

            catch (MalformedURLException e)
                { return new Ret2<URL, MalformedURLException>(null, e); }


        if (src.startsWith("../"))
        {
            String  sourcePageStr   = sourcePage.toString();
            short   nLevels         = 0;

            do
                { nLevels++;  src = src.substring(3); }
            while (src.startsWith("../"));

            String  directory = StringParse.dotDotParentDirectory(sourcePage.toString(), nLevels);

            try
                { return new Ret2<URL, MalformedURLException>(new URL(directory + src), null); }

            catch (MalformedURLException e)
                { return new Ret2<URL, MalformedURLException>(null, e); }

            catch (Exception e)
            { 
                return new Ret2<URL, MalformedURLException>
                    (null,
                    new MalformedURLException(e.getClass().getCanonicalName() +
                    ":" + e.getMessage())
                    );
            }
        }


        String  root =
            sourcePage.getProtocol().toLowerCase() + "://" + 
            sourcePage.getHost().toLowerCase();

        String  path    = sourcePage.getPath().trim();
        int     pos     = StringParse.findLastFrontSlashPos(path);

        if (pos == -1) throw new StringIndexOutOfBoundsException(
            "The URL you have provided: " + sourcePage.toString() +
            " does not have a '/' front-slash character in it's path." +
            "Cannot proceed resolving relative-URL's without this."
        );

        path = path.substring(0, pos + 1);

        try
            { return new Ret2<URL, MalformedURLException>(new URL(root + path + src), null); }

        catch (MalformedURLException e)
            { return new Ret2<URL, MalformedURLException>(null, e); }
    }
}