1
/* -*- Mode: JavaScript; coding: utf-8; tab-width: 3; indent-tabs-mode: tab; c-basic-offset: 3 -*-
2
*******************************************************************************
4
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
6
* Copyright create3000, Scheffelstraße 31a, Leipzig, Germany 2011.
8
* All rights reserved. Holger Seelig <holger.seelig@yahoo.de>.
10
* The copyright notice above does not evidence any actual of intended
11
* publication of such source code, and is an unpublished work by create3000.
12
* This material contains CONFIDENTIAL INFORMATION that is the property of
15
* No permission is granted to copy, distribute, or create derivative works from
16
* the contents of this software, in whole or in part, without the prior written
17
* permission of create3000.
19
* NON-MILITARY USE ONLY
21
* All create3000 software are effectively free software with a non-military use
22
* restriction. It is free. Well commented source is provided. You may reuse the
23
* source in any way you please with the exception anything that uses it must be
24
* marked to indicate is contains 'non-military use only' components.
26
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
28
* Copyright 2015, 2016 Holger Seelig <holger.seelig@yahoo.de>.
30
* This file is part of the Cobweb Project.
32
* Cobweb is free software: you can redistribute it and/or modify it under the
33
* terms of the GNU General Public License version 3 only, as published by the
34
* Free Software Foundation.
36
* Cobweb is distributed in the hope that it will be useful, but WITHOUT ANY
37
* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
38
* A PARTICULAR PURPOSE. See the GNU General Public License version 3 for more
39
* details (a copy is included in the LICENSE file that accompanied this code).
41
* You should have received a copy of the GNU General Public License version 3
42
* along with Cobweb. If not, see <http://www.gnu.org/licenses/gpl.html> for a
43
* copy of the GPLv3 License.
45
* For Silvio, Joy and Adi.
47
******************************************************************************/
61
function Path (path, separator)
63
switch (arguments .length)
67
this .value = path .split (separator);
68
this .value .separator = separator;
69
this .value .leadingSeparator = false;
70
this .value .trailingSeparator = false;
72
if (this .value .length)
74
if (this .value [0] === "")
76
this .value .shift ();
77
this .value .leadingSeparator = true;
81
if (this .value .length)
83
if (this .value [this .value .length - 1] === "")
86
this .value .trailingSeparator = true;
94
this .value = arguments [0];
95
this .value .separator = arguments [1];
96
this .value .leadingSeparator = arguments [2];
97
this .value .trailingSeparator = arguments [3];
107
return new Path (this .value .slice (0, this .value .length),
108
this .value .separator,
109
this .value .leadingSeparator,
110
this .value .trailingSeparator);
114
return new Path ([ ],
115
this .value .separator,
121
if (this .value .trailingSeparator)
122
return this .copy ();
128
switch (this .value .length)
133
if (this .value .leadingSeparator)
136
return new Path ([ ".." ], this .value .separator, false, false);
140
return new Path (this .value .slice (0, this .value .length - 1),
141
this .value .separator,
142
this .value .leadingSeparator,
147
isRelative: function ()
149
return ! this .value .length || this .value [0] == "..";
151
getRelativePath: function (descendant)
153
if (this .isRelative ())
156
var path = new Path ([ ], "/", false, false);
158
var basePath = this .removeDotSegments () .base;
159
var descendantPath = descendant .removeDotSegments ();
163
for (i = 0; i < basePath .value .length && i < descendantPath .value .length; ++ i)
165
if (basePath .value [i] !== descendantPath .value [i])
169
for (j = i; j < basePath .value .length; ++ j)
170
path .value .push ("..");
172
for (j = i; j < descendantPath .value .length; ++ j)
173
path .value .push (descendantPath .value [j]);
177
removeDotSegments: function ()
179
var path = new Path ([ ], this .value .separator, this .value .leadingSeparator, this .value .trailingSeparator);
181
if (this .value .length)
183
for (var i = 0; i < this .value .length; ++ i)
185
var segment = this .value [i];
188
path .value .trailingSeparator = true;
190
else if (segment === "..")
192
path .value .trailingSeparator = true;
194
if (path .value .length)
200
path .value .trailingSeparator = false;
201
path .value .push (segment);
205
path .value .trailingSeparator |= this .value .trailingSeparator;
210
toString: function ()
214
if (this .value .leadingSeparator)
215
string += this .value .separator;
217
string += this .value .join (this .value .separator);
219
if (this .value .trailingSeparator)
220
string += this .value .separator;
228
* https://tools.ietf.org/html/rfc3986
239
var address = /^(?:([^:\/?#]*?):)?(?:(\/\/)([^\/?#]*))?([^?#]*)(?:\?([^#]*))?(?:#(.*))?$/;
240
var authority = /^(.*?)(?:\:([^:]*))?$/;
242
function parse (uri, string)
244
var result = address .exec (string);
248
uri .scheme = result [1] || "";
249
uri .slashs = result [2] || "";
250
uri .authority = result [3] || "";
251
uri .path = result [4] || "";
252
uri .query = result [5] || "";
253
uri .fragment = result [6] || "";
255
var result = authority .exec (uri .authority);
259
uri .host = result [1] || "";
260
uri .port = result [2] ? parseInt (result [2]) : 0;
261
uri .authority = uri .host;
264
uri .authority += ":" + uri .port;
267
uri .absolute = Boolean (uri .slashs .length) || uri .path [0] === "/";
268
uri .local = /^(?:file|data)$/ .test (uri .scheme) || (! uri .scheme && ! uri .authority)
271
uri .string = string;
274
function removeDotSegments (path)
276
return new Path (path, "/") .removeDotSegments () .toString ();
296
switch (arguments .length)
302
parse (this .value, uri);
307
this .value .local = arguments [0];
308
this .value .absolute = arguments [1];
309
this .value .scheme = arguments [2];
310
this .value .slashs = arguments [3];
311
this .value .authority = arguments [4];
312
this .value .host = arguments [5];
313
this .value .port = arguments [6];
314
this .value .path = arguments [7];
315
this .value .query = arguments [8];
316
this .value .fragment = arguments [9];
317
this .value .string = this .toString ();
327
return new URI (this .value .local,
328
this .value .absolute,
331
this .value .authority,
336
this .value .fragment);
340
return this .value .string .length;
342
isRelative: function ()
344
return ! this .value .absolute ();
346
isAbsolute: function ()
348
return ! this .value .absolute;
352
return this .value .local;
354
isNetwork: function ()
356
return ! this .value .local;
358
isDirectory: function ()
360
if (this .value .path .length == 0)
361
return this .isNetwork ();
363
return this .value .path [this .value .path .length - 1] === "/";
367
return ! this .isDirectory ();
373
hierarchy += this .value .slashs;
374
hierarchy += this .value .authority;
375
hierarchy += this .value .path;
381
return this .value .authority;
385
return this .value .scheme;
389
return this .value .host;
393
return this .value .port;
397
var wellKnownPort = wellKnownPorts [this .value .scheme];
399
if (wellKnownPort !== undefined)
400
return wellKnownPort;
406
return this .value .path;
410
this .value .query = value;
414
return this .value .query;
418
this .value .fragment = value;
422
return this .value .fragment;
426
return this .toString ();
430
return new URI (this .value .local,
431
this .value .absolute,
434
this .value .authority,
437
this .value .local ? "/" : "",
443
if (this .isDirectory ())
444
return new URI (this .value .local,
445
this .value .absolute,
448
this .value .authority,
461
if (this .isDirectory ())
463
if (this .value .path .length == 1)
466
path = this .value .path .substr (0, this .value .path .length - 1);
471
var slash = path .lastIndexOf ("/");
473
path = slash == -1 ? "" : path .substring (0, path .lastIndexOf ("/") + 1);
475
return new URI (this .value .local,
476
this .value .absolute,
479
this .value .authority,
488
return new URI (this .value .local,
489
this .value .absolute,
492
this .value .authority,
501
if (this .value .path)
502
return this .value .path .substr (this .value .path. lastIndexOf ("/") + 1);
508
if (this .value .path .length && this .isFile ())
510
var basename = this .basename;
511
var suffix = this .suffix;
513
return basename .substr (0, basename .length - suffix .length);
516
return this .basename;
520
var dot = this .value .path .lastIndexOf (".");
521
var slash = this .value .path .lastIndexOf ("/");
524
return this .value .path .substr (dot);
528
transform: function (reference)
531
var T_absolute = false;
535
var T_authority = "";
542
if (reference .scheme .length)
544
T_local = reference .isLocal ();
545
T_absolute = reference .isAbsolute ();
546
T_scheme = reference .scheme;
547
T_slashs = reference .value .slashs;
548
T_authority = reference .authority;
549
T_host = reference .host;
550
T_port = reference .port;
551
T_path = reference .path;
552
T_query = reference .query;
556
if (reference .authority .length)
558
T_local = reference .isLocal ();
559
T_absolute = reference .isAbsolute ();
560
T_authority = reference .authority;
561
T_host = reference .host;
562
T_port = reference .port;
563
T_path = reference .path;
564
T_query = reference .query;
568
if (reference .path .length === 0)
570
var T_path = this .value .path;
572
if (reference .query .length)
573
T_query = reference .query;
575
T_query = this .value .query;
579
if (reference .path [0] === "/")
581
T_path = reference .path;
585
// merge (Base .path (), reference .path ());
587
var base = this .base;
589
if (base .path .length === 0)
592
T_path += base .path;
594
T_path += reference .path;
597
T_query = reference .query;
600
T_local = this .isLocal ();
601
T_absolute = this .isAbsolute () || reference .isAbsolute ();
602
T_authority = this .value .authority;
603
T_host = this .value .host;
604
T_port = this .value .port;
607
T_scheme = this .value .scheme;
608
T_slashs = this .value .slashs;
611
T_fragment = reference .fragment;
613
return new URI (T_local,
620
removeDotSegments (T_path),
624
removeDotSegments: function ()
626
return new URI (this .value .local,
627
this .value .absolute,
630
this .value .authority,
633
removeDotSegments (this .value .path),
635
this .value .fragment);
637
getRelativePath: function (descendant)
639
if (this .value .scheme !== descendant .scheme)
642
if (this .value .authority !== descendant .authority)
645
var path = new Path (this .value .path, "/");
646
var descendantPath = new Path (descendant .path, "/");
648
return new URI (true,
655
path .getRelativePath (descendantPath) .toString (),
657
descendant .fragment);
661
return new URI (escape (this .location));
663
unescape: function ()
665
return new URI (unescape (this .location));
667
toString: function ()
669
var string = this .value .scheme;
671
if (this .value .scheme .length)
674
string += this .hierarchy;
676
if (this .value .query .length)
677
string += "?" + this .value .query;
679
if (this .value .fragment .length)
680
string += "#" + this .value .fragment;