source: trunk/docx4j/src/main/java/org/docx4j/openpackaging/URIHelper.java @ 676

Revision 676, 17.4 KB checked in by jharrop, 3 years ago (diff)

logging

  • Property svn:eol-style set to native
Line 
1/*
2 * Copyright (c) 2006, Wygwam
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without modification,
6 * are permitted provided that the following conditions are met:
7 *
8 * - Redistributions of source code must retain the above copyright notice,
9 * this list of conditions and the following disclaimer.
10 * - Redistributions in binary form must reproduce the above copyright notice,
11 * this list of conditions and the following disclaimer in the documentation and/or
12 * other materials provided with the distribution.
13 * - Neither the name of Wygwam nor the names of its contributors may be
14 * used to endorse or promote products derived from this software without
15 * specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
18 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20 * IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
22 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
24 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
25 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28package org.docx4j.openpackaging;
29
30import java.net.URI;
31import java.net.URISyntaxException;
32
33import org.apache.log4j.Logger;
34
35import org.docx4j.openpackaging.contenttype.ContentTypes;
36import org.docx4j.openpackaging.exceptions.InvalidFormatException;
37import org.docx4j.openpackaging.exceptions.InvalidOperationException;
38import org.docx4j.openpackaging.parts.PartName;
39
40
41
42/**
43 * Helper for part and pack URI.
44 *
45 * @author Julien Chable, CDubet
46 * @version 0.3
47 */
48public final class URIHelper {
49
50        private static Logger log = Logger.getLogger(URIHelper.class); 
51       
52        /**
53         * Package root URI.
54         */
55        private static URI packageRootUri;
56
57        /**
58         * Extension name of a relationship part.
59         */
60        public static final String RELATIONSHIP_PART_EXTENSION_NAME;
61
62        /**
63         * Segment name of a relationship part.
64         */
65        public static final String RELATIONSHIP_PART_SEGMENT_NAME;
66
67        /**
68         * Segment name of the package properties folder.
69         */
70        public static final String PACKAGE_PROPERTIES_SEGMENT_NAME;
71
72        /**
73         * Core package properties art name.
74         */
75        public static final String PACKAGE_CORE_PROPERTIES_NAME;
76
77        /**
78         * Forward slash URI separator.
79         */
80        public static final char FORWARD_SLASH_CHAR;
81
82        /**
83         * Forward slash URI separator.
84         */
85        public static final String FORWARD_SLASH_STRING;
86
87        /**
88         * Package relationships part URI
89         */
90        public static final URI PACKAGE_RELATIONSHIPS_ROOT_URI;
91
92        /**
93         * Package relationships part name.
94         */
95        public static final PartName PACKAGE_RELATIONSHIPS_ROOT_PART_NAME;
96
97        /**
98         * Core properties part URI.
99         */
100        public static final URI CORE_PROPERTIES_URI;
101
102        /**
103         * Core properties partname.
104         */
105        public static final PartName CORE_PROPERTIES_PART_NAME;
106
107        /**
108         * Root package URI.
109         */
110        public static final URI PACKAGE_ROOT_URI;
111
112        /**
113         * Root package part name.
114         */
115        public static final PartName PACKAGE_ROOT_PART_NAME;
116
117        /* Static initialization */
118        static {
119                RELATIONSHIP_PART_SEGMENT_NAME = "_rels";
120                RELATIONSHIP_PART_EXTENSION_NAME = ".rels";
121                FORWARD_SLASH_CHAR = '/';
122                FORWARD_SLASH_STRING = "/";
123                PACKAGE_PROPERTIES_SEGMENT_NAME = "docProps";
124                PACKAGE_CORE_PROPERTIES_NAME = "core.xml";
125
126                // Make URI
127                URI uriPACKAGE_ROOT_URI = null;
128                URI uriPACKAGE_RELATIONSHIPS_ROOT_URI = null;
129                URI uriPACKAGE_PROPERTIES_URI = null;
130                try {
131                        uriPACKAGE_ROOT_URI = new URI("/");
132                        uriPACKAGE_RELATIONSHIPS_ROOT_URI = new URI(FORWARD_SLASH_CHAR
133                                        + RELATIONSHIP_PART_SEGMENT_NAME + FORWARD_SLASH_CHAR
134                                        + RELATIONSHIP_PART_EXTENSION_NAME);
135                        packageRootUri = new URI("/");
136                        uriPACKAGE_PROPERTIES_URI = new URI(FORWARD_SLASH_CHAR
137                                        + PACKAGE_PROPERTIES_SEGMENT_NAME + FORWARD_SLASH_CHAR
138                                        + PACKAGE_CORE_PROPERTIES_NAME);
139                } catch (URISyntaxException e) {
140                        // Should never happen in production as all data are fixed
141                }
142                PACKAGE_ROOT_URI = uriPACKAGE_ROOT_URI;
143                PACKAGE_RELATIONSHIPS_ROOT_URI = uriPACKAGE_RELATIONSHIPS_ROOT_URI;
144                CORE_PROPERTIES_URI = uriPACKAGE_PROPERTIES_URI;
145
146                // Make part name from previous URI
147                PartName tmpPACKAGE_ROOT_PART_NAME = null;
148                PartName tmpPACKAGE_RELATIONSHIPS_ROOT_PART_NAME = null;
149                PartName tmpCORE_PROPERTIES_URI = null;
150                try {
151                        tmpPACKAGE_RELATIONSHIPS_ROOT_PART_NAME = createPartName(PACKAGE_RELATIONSHIPS_ROOT_URI);
152                        tmpCORE_PROPERTIES_URI = createPartName(CORE_PROPERTIES_URI);
153                        tmpPACKAGE_ROOT_PART_NAME = new PartName(PACKAGE_ROOT_URI,
154                                        false);
155                } catch (InvalidFormatException e) {
156                        // Should never happen in production as all data are fixed
157                }
158                PACKAGE_RELATIONSHIPS_ROOT_PART_NAME = tmpPACKAGE_RELATIONSHIPS_ROOT_PART_NAME;
159                CORE_PROPERTIES_PART_NAME = tmpCORE_PROPERTIES_URI;
160                PACKAGE_ROOT_PART_NAME = tmpPACKAGE_ROOT_PART_NAME;
161        }
162
163        /**
164         * Gets the URI for the package root.
165         *
166         * @return URI of the package root.
167         */
168        public static URI getPackageRootUri() {
169                return packageRootUri;
170        }
171
172
173        /**
174         * Know if the specified URI is a relationship part name.
175         *
176         * @param partUri
177         *            URI to check.
178         * @return <i>true</i> if the URI <i>false</i>.
179         */
180        private static boolean isRelationshipPartURI(URI partUri) {
181                if (partUri == null)
182                        throw new NullPointerException("partUri");
183
184                return partUri.getPath().matches(
185                                ".*" + RELATIONSHIP_PART_SEGMENT_NAME + ".*"
186                                                + RELATIONSHIP_PART_EXTENSION_NAME + "$");
187        }
188
189        /**
190         * Get file name from the specified URI.
191         */
192        public static String getFilename(URI uri) {
193                if (uri != null) {
194                        String path = uri.getPath();
195                        int len = path.length();
196                        int num2 = len;
197                        while (--num2 >= 0) {
198                                char ch1 = path.charAt(num2);
199                                if (ch1 == URIHelper.FORWARD_SLASH_CHAR)
200                                        return path.substring(num2 + 1, len);
201                        }
202                }
203                return "";
204        }
205
206        /**
207         * Get the file name without the trailing extension.
208         */
209        public static String getFilenameWithoutExtension(URI uri) {
210                String filename = getFilename(uri);
211                int dotIndex = filename.lastIndexOf(".");
212                if (dotIndex == -1)
213                        return filename;
214                return filename.substring(0, dotIndex);
215        }
216
217        /**
218         * Get the directory path from the specified URI.
219         */
220        public static URI getPath(URI uri) {
221                if (uri != null) {
222                        String path = uri.getPath();
223                        int len = path.length();
224                        int num2 = len;
225                        while (--num2 >= 0) {
226                                char ch1 = path.charAt(num2);
227                                if (ch1 == URIHelper.FORWARD_SLASH_CHAR) {
228                                        try {
229                                                return new URI(path.substring(0, num2));
230                                        } catch (URISyntaxException e) {
231                                                return null;
232                                        }
233                                }
234                        }
235                }
236                return null;
237        }
238
239        /**
240         * Combine two URI.
241         *
242         * @param prefix
243         * @param suffix
244         * @return
245         */
246        public static URI combine(URI prefix, URI suffix) {
247                URI retUri = null;
248                try {
249                        retUri = new URI(combine(prefix.getPath(), suffix.getPath()));
250                } catch (URISyntaxException e) {
251                        throw new IllegalArgumentException(
252                                        "Prefix and suffix can't be combined !");
253                }
254                return retUri;
255        }
256
257        /**
258         * Combine a string URI with a prefix and a suffix.
259         */
260        public static String combine(String prefix, String suffix) {
261                if (!prefix.endsWith("" + FORWARD_SLASH_CHAR)
262                                && !suffix.startsWith("" + FORWARD_SLASH_CHAR))
263                        return prefix + FORWARD_SLASH_CHAR + suffix;
264                else if ((!prefix.endsWith("" + FORWARD_SLASH_CHAR)
265                                && suffix.startsWith("" + FORWARD_SLASH_CHAR) || (prefix
266                                .endsWith("" + FORWARD_SLASH_CHAR) && !suffix.startsWith(""
267                                + FORWARD_SLASH_CHAR))))
268                        return prefix + suffix;
269                else
270                        return "";
271        }
272
273        /**
274         * Fully relativize the target part URI against the source part URI.
275         *
276         * @param sourceURI
277         *            The source part URI.
278         * @param targetURI
279         *            The target part URI.
280         * @return A fully relativize part name URI ('word/media/image1.gif',
281         *         '/word/document.xml' => 'media/image1.gif') else
282         *         <code>null</code>.
283         */
284        public static URI relativizeURI(URI sourceURI, URI targetURI) {
285                StringBuilder retVal = new StringBuilder();
286                String[] segmentsSource = sourceURI.getPath().split("/", -1);
287                String[] segmentsTarget = targetURI.getPath().split("/", -1);
288
289                // If the source URI is empty
290                if (segmentsSource.length == 0) {
291                        throw new IllegalArgumentException(
292                                        "Can't relativize an empty source URI !");
293                }
294
295                // If target URI is empty
296                if (segmentsTarget.length == 0) {
297                        throw new IllegalArgumentException(
298                                        "Can't relativize an empty target URI !");
299                }
300               
301                // If the source is the root, then the relativized
302                //  form must actually be an absolute URI
303                if(sourceURI.toString().equals("/")) {
304                        return targetURI;
305                }
306
307
308                // Relativize the source URI against the target URI.
309                // First up, figure out how many steps along we can go
310                // and still have them be the same
311                int segmentsTheSame = 0;
312                for (int i = 0; i < segmentsSource.length && i < segmentsTarget.length; i++) {
313                        if (segmentsSource[i].equals(segmentsTarget[i])) {
314                                // Match so far, good
315                                segmentsTheSame++;
316                        } else {
317                                break;
318                        }
319                }
320
321                // If we didn't have a good match or at least except a first empty element
322                if ((segmentsTheSame == 0 || segmentsTheSame == 1) &&
323                                segmentsSource[0].equals("") && segmentsTarget[0].equals("")) {
324                        for (int i = 0; i < segmentsSource.length - 2; i++) {
325                                retVal.append("../");
326                        }
327                        for (int i = 0; i < segmentsTarget.length; i++) {
328                                if (segmentsTarget[i].equals(""))
329                                        continue;
330                                retVal.append(segmentsTarget[i]);
331                                if (i != segmentsTarget.length - 1)
332                                        retVal.append("/");
333                        }
334
335                        try {
336                                return new URI(retVal.toString());
337                        } catch (Exception e) {
338                                System.err.println(e);
339                                return null;
340                        }
341                }
342
343                // Special case for where the two are the same
344                if (segmentsTheSame == segmentsSource.length
345                                && segmentsTheSame == segmentsTarget.length) {
346                        retVal.append("");
347                } else {
348                        // Matched for so long, but no more
349
350                        // Do we need to go up a directory or two from
351                        // the source to get here?
352                        // (If it's all the way up, then don't bother!)
353                        if (segmentsTheSame == 1) {
354                                retVal.append("/");
355                        } else {
356                                for (int j = segmentsTheSame; j < segmentsSource.length - 1; j++) {
357                                        retVal.append("../");
358                                }
359                        }
360
361                        // Now go from here on down
362                        for (int j = segmentsTheSame; j < segmentsTarget.length; j++) {
363                                if (retVal.length() > 0
364                                                && retVal.charAt(retVal.length() - 1) != '/') {
365                                        retVal.append("/");
366                                }
367                                retVal.append(segmentsTarget[j]);
368                        }
369                }
370
371                try {
372                        return new URI(retVal.toString());
373                } catch (Exception e) {
374                        System.err.println(e);
375                        return null;
376                }
377        }
378       
379
380        /**
381         * Resolve a target uri against a source.
382         *
383         * @param sourcePartUri
384         *            The source URI.
385         * @param targetUri
386         *            The target URI.
387         * @return The resolved URI.
388         */
389        public static URI resolvePartUri(URI sourcePartUri, URI targetUri) {
390//              log.info("source: " + sourcePartUri);
391//              log.info("target: " + targetUri);
392                URI uri;
393                if (sourcePartUri == null || sourcePartUri.isAbsolute()) {
394                        throw new IllegalArgumentException("sourcePartUri");
395                }
396                if (targetUri == null) {
397                        log.error("targetUri was null");
398                        throw new IllegalArgumentException("targetUri");                       
399                } else if (targetUri.isAbsolute()) {                   
400                        log.error("targetUri " + targetUri.toString() + " is absolute!");
401                        throw new IllegalArgumentException("targetUri");
402                }
403
404                uri = sourcePartUri.resolve(targetUri);
405//              log.info("RESULT: " + uri);
406                return uri;
407        }
408
409        /**
410         * Get URI from a string path.
411         */
412        public static URI getURIFromPath(String path) {
413                URI retUri = null;
414                try {
415                        retUri = new URI(path);
416                } catch (URISyntaxException e) {
417                        throw new IllegalArgumentException("path");
418                }
419                return retUri;
420        }
421
422        public static URI getSourcePartUriFromRelationshipPartUri(
423                        URI relationshipPartUri) {
424                if (relationshipPartUri == null)
425                        throw new IllegalArgumentException(
426                                        "The relationshipPart Uri was null !");
427
428                if (!isRelationshipPartURI(relationshipPartUri))
429                        throw new IllegalArgumentException(
430                                        "L'URI ne doit pas ᅵtre celle d'une partie de type relation.");
431
432                if (relationshipPartUri.compareTo(PACKAGE_RELATIONSHIPS_ROOT_URI) == 0)
433                        return PACKAGE_ROOT_URI;
434
435                String filename = relationshipPartUri.getPath();
436                String filenameWithoutExtension = getFilenameWithoutExtension(relationshipPartUri);
437                filename = filename
438                                .substring(0, ((filename.length() - filenameWithoutExtension
439                                                .length()) - RELATIONSHIP_PART_EXTENSION_NAME.length()));
440                filename = filename.substring(0, filename.length()
441                                - RELATIONSHIP_PART_SEGMENT_NAME.length() - 1);
442                filename = combine(filename, filenameWithoutExtension);
443                return getURIFromPath(filename);
444        }
445
446        /**
447         * Create an OPC compliant part name by throwing an exception if the URI is
448         * not valid.
449         *
450         * @param partUri
451         *            The part name URI to validate.
452         * @return A valid part name object, else <code>null</code>.
453         * @throws InvalidFormatException
454         *             Throws if the specified URI is not OPC compliant.
455         */
456        public static PartName createPartName(URI partUri)
457                        throws InvalidFormatException {
458                if (partUri == null)
459                        throw new IllegalArgumentException("partName");
460
461                return new PartName(partUri, true);
462        }
463
464        /**
465         * Create an OPC compliant part name by throwing an exception if the
466         * specified name is not valid.
467         *
468         * @param partName
469         *            The part name to validate.
470         * @return The correspondant part name if valid, else <code>null</code>.
471         * @throws InvalidFormatException
472         *             Throws if the specified part name is not OPC compliant.
473         * @see #createPartName(URI)
474         */
475        public static PartName createPartName(String partName)
476                        throws InvalidFormatException {
477                URI partNameURI;
478                try {
479                        partNameURI = new URI(partName);
480                } catch (URISyntaxException e) {
481                        throw new InvalidFormatException(e.getMessage());
482                }
483                return createPartName(partNameURI);
484        }
485
486        /**
487         * Validate a part URI by returning a boolean.
488         * ([M1.1],[M1.3],[M1.4],[M1.5],[M1.6])
489         *
490         * (OPC Specifications 8.1.1 Part names) :
491         *
492         * Part Name Syntax
493         *
494         * The part name grammar is defined as follows:
495         *
496         * <i>part_name = 1*( "/" segment )
497         *
498         * segment = 1*( pchar )</i>
499         *
500         *
501         * (pchar is defined in RFC 3986)
502         *
503         * @param partUri
504         *            The URI to validate.
505         * @return <b>true</b> if the URI is valid to the OPC Specifications, else
506         *         <b>false</b>
507         *
508         * @see #createPartName(URI)
509         */
510        public static boolean isValidPartName(URI partUri) {
511                if (partUri == null)
512                        throw new IllegalArgumentException("partUri");
513
514                try {
515                        createPartName(partUri);
516                        return true;
517                } catch (Exception e) {
518                        return false;
519                }
520        }
521
522        /**
523         * Decode a URI by converting all percent encoded character into a String
524         * character.
525         *
526         * @param uri
527         *            The URI to decode.
528         * @return The specified URI in a String with converted percent encoded
529         *         characters.
530         */
531        public static String decodeURI(URI uri) {
532                StringBuffer retVal = new StringBuffer();
533                String uriStr = uri.toASCIIString();
534                char c;
535                for (int i = 0; i < uriStr.length(); ++i) {
536                        c = uriStr.charAt(i);
537                        if (c == '%') {
538                                // We certainly found an encoded character, check for length
539                                // now ( '%' HEXDIGIT HEXDIGIT)
540                                if (((uriStr.length() - i) < 2)) {
541                                        throw new IllegalArgumentException("The uri " + uriStr
542                                                        + " contain invalid encoded character !");
543                                }
544
545                                // Decode the encoded character
546                                char decodedChar = (char) Integer.parseInt(uriStr.substring(
547                                                i + 1, i + 3), 16);
548                                retVal.append(decodedChar);
549                                i += 2;
550                                continue;
551                        }
552                        retVal.append(c);
553                }
554                return retVal.toString();
555        }
556
557//      /**
558//       * Fully relativize the source part URI against the target part URI.
559//       *
560//       * @param sourceURI
561//       *            The source part URI.
562//       * @param targetURI
563//       *            The target part URI.
564//       * @return A fully relativize part name URI ('word/media/image1.gif',
565//       *         '/word/document.xml' => 'media/image1.gif') else
566//       *         <code>null</code>.
567//       */
568//      public static URI OLDrelativizeURI(URI sourceURI, URI targetURI) {
569//              StringBuffer retVal = new StringBuffer();
570//              String[] segmentsSource = sourceURI.getPath().split("/");
571//              String[] segmentsTarget = targetURI.getPath().split("/");
572//
573//              // If the source URI is empty
574//              if (segmentsSource.length == 0) {
575//                      return null;
576//              }
577//
578//              // If target URI is empty
579//              if (segmentsTarget.length == 0) {
580//                      if (sourceURI.getPath().startsWith(FORWARD_SLASH_STRING)) {
581//                              try {
582//                                      return new URI(sourceURI.getPath().substring(1));
583//                              } catch (Exception e) {
584//                                      return null;
585//                              }
586//                      } else
587//                              return sourceURI;
588//              }
589//
590//              // Relativize the source URI against the target URI.
591//              for (short i = 0, j = 0; i < segmentsSource.length
592//                              && j < segmentsTarget.length; ++i, ++j) {
593//                      if (segmentsSource[i].equalsIgnoreCase(segmentsTarget[j])) {
594//                              if (i < segmentsSource.length - 1) {
595//                                      continue;
596//                              } else {
597//                                      // We add the last segment whatever it happens
598//                                      retVal.append("/");
599//                                      retVal.append(segmentsTarget[i]);
600//                                      break;
601//                              }
602//                      } else {
603//                              for (; i < segmentsSource.length; ++i) {
604//                                      retVal.append("/");
605//                                      retVal.append(segmentsSource[i]);
606//                              }
607//                              break;
608//                      }
609//              }
610//              try {
611//                      PartName retPartName = new PartName(
612//                                      retVal.toString(), true);
613//                      return new URI(retPartName.getURI().getPath().substring(1));
614//              } catch (Exception e) {
615//                      return null;
616//              }
617//      }
618
619       
620       
621}
Note: See TracBrowser for help on using the repository browser.