Content of file PathNormalization.java.html

<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"><html xmlns="http://www.w3.org/1999/xhtml" lang="en"><head><meta http-equiv="Content-Type" content="text/html;charset=UTF-8"/><link rel="stylesheet" href="../../jacoco-resources/report.css" type="text/css"/><link rel="shortcut icon" href="../../jacoco-resources/report.gif" type="image/gif"/><title>PathNormalization.java</title><link rel="stylesheet" href="../../jacoco-resources/prettify.css" type="text/css"/><script type="text/javascript" src="../../jacoco-resources/prettify.js"></script></head><body onload="window['PR_TAB_WIDTH']=4;prettyPrint()"><div class="breadcrumb" id="breadcrumb"><span class="info"><a href="../../jacoco-sessions.html" class="el_session">Sessions</a></span><a href="../../index.html" class="el_report">blueMarine II :: Catalog</a> &gt; <a href="../index.html" class="el_bundle">it-tidalwave-bluemarine2-commons</a> &gt; <a href="index.source.html" class="el_package">it.tidalwave.bluemarine2.util</a> &gt; <span class="el_source">PathNormalization.java</span></div><h1>PathNormalization.java</h1><pre class="source lang-java linenums">/*
 * *********************************************************************************************************************
 *
 * blueMarine II: Semantic Media Centre
 * http://tidalwave.it/projects/bluemarine2
 *
 * Copyright (C) 2015 - 2021 by Tidalwave s.a.s. (http://tidalwave.it)
 *
 * *********************************************************************************************************************
 *
 * Licensed under the Apache License, Version 2.0 (the &quot;License&quot;); you may not use this file except in compliance with
 * the License. You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on
 * an &quot;AS IS&quot; BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the License for the
 * specific language governing permissions and limitations under the License.
 *
 * *********************************************************************************************************************
 *
 * git clone https://bitbucket.org/tidalwave/bluemarine2-src
 * git clone https://github.com/tidalwave-it/bluemarine2-src
 *
 * *********************************************************************************************************************
 */
package it.tidalwave.bluemarine2.util;

import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import java.text.Normalizer;
import java.util.Objects;
import java.util.Optional;
import java.util.stream.Stream;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import it.tidalwave.util.annotation.VisibleForTesting;
import lombok.experimental.UtilityClass;
import lombok.extern.slf4j.Slf4j;
import static java.text.Normalizer.Form.*;

/***********************************************************************************************************************
 *
 * See the related test for detailed information.
 *
 * @author  Fabrizio Giudici
 *
 **********************************************************************************************************************/
<span class="pc bpc" id="L51" title="1 of 2 branches missed.">@UtilityClass @Slf4j</span>
<span class="nc" id="L52">public class PathNormalization</span>
  {
    private static final Normalizer.Form NATIVE_FORM;

    static
      {
<span class="fc" id="L58">        final String osName = System.getProperty(&quot;os.name&quot;).toLowerCase();</span>

<span class="pc bpc" id="L60" title="3 of 4 branches missed.">        switch (osName)</span>
          {
            case &quot;linux&quot;:
<span class="fc" id="L63">                NATIVE_FORM = NFC;</span>
<span class="fc" id="L64">                break;</span>

            case &quot;mac os x&quot;:
<span class="nc" id="L67">                NATIVE_FORM = NFD;</span>
<span class="nc" id="L68">                break;</span>

            case &quot;windows&quot;:
<span class="nc" id="L71">                NATIVE_FORM = NFD; // FIXME: just guessing</span>
just guessing
<span class="nc" id="L72"> break;</span> default: <span class="nc" id="L75"> throw new ExceptionInInitializerError(&quot;Unknown o.s.: &quot; + osName);</span> } <span class="fc" id="L78"> log.info(&quot;Charset normalizer form: {}&quot;, NATIVE_FORM);</span> <span class="fc" id="L79"> }</span> /******************************************************************************************************************* * * Takes a path that maps to an existing file, and in case it can't be resolved, it tries to replace with an * equivalent representation of an existing path, with the native form of character encoding (i.e. the one used * by the file system). * If there is no normalized path to replace with, the original path is returned. * Note that this method is I/O heavy, as it must access the file system. * FIXME: what about using a cache? * * See http://askubuntu.com/questions/533690/rsync-with-special-character-files-not-working-between-mac-and-linux * * @param path the path * @return the normalized path * ******************************************************************************************************************/ @Nonnull public static Path fixedPath (@Nonnull final Path path) throws IOException { // log.trace(&quot;fixedPath({})&quot;, path); <span class="fc bfc" id="L102" title="All 2 branches covered."> if (Files.exists(path)) // can be normally found, no need to process it</span> { <span class="fc" id="L104"> return path;</span> } <span class="fc" id="L107"> Path pathSoFar = Paths.get(&quot;/&quot;);</span> <span class="fc bfc" id="L109" title="All 2 branches covered."> for (final Path segment : path.toAbsolutePath())</span> { // log.trace(&quot;&gt;&gt;&gt;&gt; pathSoFar: {} segment: {}&quot;, pathSoFar, segment); <span class="fc" id="L112"> final Path resolved = pathSoFar.resolve(segment);</span> <span class="fc bfc" id="L114" title="All 2 branches covered."> if (Files.exists(resolved))</span> { <span class="fc" id="L116"> pathSoFar = resolved;</span> } else // didn't find 'resolved' because of wrong normalisation, searching in alternative way { <span class="fc" id="L120"> try (final Stream&lt;Path&gt; stream = Files.list(pathSoFar))</span> { <span class="fc" id="L122"> final Optional&lt;Path&gt; child = stream.map(Path::getFileName)</span> <span class="fc" id="L123"> .filter(p -&gt; equalsNormalized(segment, p))</span> <span class="fc" id="L124"> .findFirst();</span> <span class="pc bpc" id="L125" title="1 of 2 branches missed."> if (child.isEmpty())</span> { <span class="nc" id="L127"> log.warn(&quot;&gt;&gt;&gt;&gt; fixing failed at: {}&quot;, pathSoFar);</span> <span class="nc" id="L128"> return path;</span> } <span class="fc" id="L131"> pathSoFar = pathSoFar.resolve(child.get());</span> <span class="pc bpc" id="L132" title="2 of 4 branches missed."> assert Files.exists(pathSoFar) : &quot;Fixing failed at: &quot; + pathSoFar;</span> <span class="nc bnc" id="L133" title="All 2 branches missed."> }</span> } <span class="fc" id="L135"> }</span> <span class="fc" id="L137"> return pathSoFar;</span> } /******************************************************************************************************************* * * Checks whether two Paths are equal after normalisation of their string representation. * * @param path1 the former path * @param path2 the latter path * @return {@code true} if they are equal * ******************************************************************************************************************/ @VisibleForTesting static boolean equalsNormalized (@Nonnull final Path path1, @Nonnull final Path path2) { <span class="fc" id="L151"> return Objects.equals(normalizedToNativeForm(path1.toString()), normalizedToNativeForm(path2.toString()));</span> } /******************************************************************************************************************* * * * ******************************************************************************************************************/ @Nullable public static String normalizedToNativeForm (@Nullable final String string) { <span class="pc bpc" id="L162" title="1 of 2 branches missed."> return (string == null) ? null : Normalizer.normalize(string, NATIVE_FORM);</span> } } </pre><div class="footer"><span class="right">Created with <a href="http://www.jacoco.org/jacoco">JaCoCo</a> 0.8.7.202105040129</span></div></body></html>