<commit_before>﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Xml;
using System.Xml.Linq;
using System.Xml.Serialization;

using Umbraco.Core.Composing;
using Umbraco.Core.IO;
using Umbraco.Core.Logging;
using uSync8.BackOffice.Configuration;

namespace uSync8.BackOffice.Services
{
    /// <summary>
    ///  putting all file actions in a service, 
    ///  so if we want to abstract later we can.
    /// </summary>
    public class SyncFileService
    {
        private uSyncSettings globalSettings;
        private string mappedRoot;
        private readonly IProfilingLogger logger;

        public SyncFileService(IProfilingLogger logger)
        {
            this.logger = logger;
            this.globalSettings = Current.Configs.uSync();
            this.mappedRoot = GetAbsPath(globalSettings.RootFolder);

            uSyncConfig.Reloaded += BackOfficeConfig_Reloaded;
        }

        private void BackOfficeConfig_Reloaded(uSyncSettings settings)
        {
            this.globalSettings = Current.Configs.uSync();
            this.mappedRoot = GetAbsPath(globalSettings.RootFolder);
        }

        public string GetAbsPath(string path)
        {
            if (IsLocalPath(path)) return CleanLocalPath(path);          
            return IOHelper.MapPath(path.TrimStart('/'));
        }

        /// <summary>
        ///  Is the Path local to a disk?
        /// </summary>
        /// <remarks>
        ///  there are .net core IsPathFullyQualified methods for this.
        /// </remarks>
        public bool IsLocalPath(string path)
        {
            // if the path is <2 it can't be a local path (e.g C:\ is min)
            if (path.Length < 2) return false;
            if (path[0] == '~') return false; // path starting with ~ is a webApp Path

            // If the first character is a directory seperator is't not a root path 
            // (e.g / or \)
            if (IsDirectorySeparator(path[0])) return false;

            return path.Length >= 3 
                && path[1] == Path.VolumeSeparatorChar 
                && IsDirectorySeparator(path[2]) 
                && IsValidDriveChar(path[0]);
        }

        private bool IsDirectorySeparator(char c)
            => c == Path.DirectorySeparatorChar || c == Path.AltDirectorySeparatorChar;

        private bool IsValidDriveChar(char value)
            => ((value >= 'A' && value <= 'Z') || (value >= 'a' && value <= 'z'));

        private string CleanLocalPath(string path)
            => path.Replace(Path.AltDirectorySeparatorChar, Path.DirectorySeparatorChar);
<commit_msg>Expand short paths, when resolving to absolute path values.<commit_after>﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Xml;
using System.Xml.Linq;
using System.Xml.Serialization;

using Umbraco.Core.Composing;
using Umbraco.Core.IO;
using Umbraco.Core.Logging;
using uSync8.BackOffice.Configuration;

namespace uSync8.BackOffice.Services
{
    /// <summary>
    ///  putting all file actions in a service, 
    ///  so if we want to abstract later we can.
    /// </summary>
    public class SyncFileService
    {
        private uSyncSettings globalSettings;
        private string mappedRoot;
        private readonly IProfilingLogger logger;

        public SyncFileService(IProfilingLogger logger)
        {
            this.logger = logger;
            this.globalSettings = Current.Configs.uSync();
            this.mappedRoot = GetAbsPath(globalSettings.RootFolder);

            uSyncConfig.Reloaded += BackOfficeConfig_Reloaded;
        }

        private void BackOfficeConfig_Reloaded(uSyncSettings settings)
        {
            this.globalSettings = Current.Configs.uSync();
            this.mappedRoot = GetAbsPath(globalSettings.RootFolder);
        }

        public string GetAbsPath(string path)
        {
            if (IsLocalPath(path)) return CleanLocalPath(path);          
            return CleanLocalPath(IOHelper.MapPath(path.TrimStart('/')));
        }

        /// <summary>
        ///  Is the Path local to a disk?
        /// </summary>
        /// <remarks>
        ///  there are .net core IsPathFullyQualified methods for this.
        /// </remarks>
        public bool IsLocalPath(string path)
        {
            // if the path is <2 it can't be a local path (e.g C:\ is min)
            if (path.Length < 2) return false;
            if (path[0] == '~') return false; // path starting with ~ is a webApp Path

            // If the first character is a directory seperator is't not a root path 
            // (e.g / or \)
            if (IsDirectorySeparator(path[0])) return false;

            return path.Length >= 3 
                && path[1] == Path.VolumeSeparatorChar 
                && IsDirectorySeparator(path[2]) 
                && IsValidDriveChar(path[0]);
        }

        private bool IsDirectorySeparator(char c)
            => c == Path.DirectorySeparatorChar || c == Path.AltDirectorySeparatorChar;

        private bool IsValidDriveChar(char value)
            => ((value >= 'A' && value <= 'Z') || (value >= 'a' && value <= 'z'));

        /// <summary>
        ///  clean up the local path, and full expand any short file names
        /// </summary>
        private string CleanLocalPath(string path)
            => Path.GetFullPath(path.Replace(Path.AltDirectorySeparatorChar, Path.DirectorySeparatorChar));

{'fraction_non_alphanumeric': 0.10614322064703745, 'fraction_numerical': 0.0036350418029807343, 'mean_word_length': 2.1249290176036344, 'pattern_counts': {'":': 0, '<': 25, '<?xml version=': 0, '>': 29, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '969249', 'n_tokens_mistral': 1522, 'n_tokens_neox': 1487, 'n_words': 406}