// ユーザーが新しいファイルの追加要求を行なうとこの実装メソッドが呼び出される。
        // このメソッドで返した ISequentialWritable<byte> は、必ず Complete されることが保証されている。
        // また、多重呼び出しがされないことが保証されている。
        protected override async Task <SequentialWritableImpl <byte> > AddFileAsyncImpl(FileContainerEntityParam param, long?fileSizeHint, CancellationToken cancel = default)
        {
            // fileParam をコピー (加工するため)
            param = param._CloneDeep();

            // ファイル名などのチェック
            if (param.MetaData.IsDirectory)
            {
                throw new ArgumentOutOfRangeException(nameof(param), "Directory is not supported.");
            }

            param.PathString._FilledOrException();
            param.PathString = PathParser.NormalizeDirectorySeparatorIncludeWindowsBackslash(param.PathString);

            if (PathParser.IsAbsolutePath(param.PathString))
            {
                throw new ArgumentOutOfRangeException(nameof(param), $"Absolute path '{param.PathString}' is not supported.");
            }

            Encoding encoding = param.GetEncoding();

            param.PathString._CheckStrSizeException(ZipConsts.MaxFileNameSize, encoding);

            Writable w = new Writable(this, param, encoding, fileSizeHint ?? long.MaxValue);

            // ローカルファイルヘッダを書き込む
            await w.StartAsync(cancel);

            // 実装クラスを経由してユーザーに渡す
            return(w);
        }
        public string MapPathPhysicalToVirtual(string?physicalPath)
        {
            if (physicalPath._IsEmpty())
            {
                return("");
            }

            physicalPath = UnderlayPathParser.NormalizeDirectorySeparatorAndCheckIfAbsolutePath(physicalPath);

            // Remove the last directory letter
            physicalPath = UnderlayPathParser.RemoveLastSeparatorChar(physicalPath);

            // the examples of physicalPath:
            // c:\view_root
            // c:\view_root\readme.txt
            // c:\view_root\abc\def\
            // c:\view_root\abc\def\readme.txt

            // delegating to the derive class
            string virtualPath = MapPathPhysicalToVirtualImpl(physicalPath);

            // the contents of virtualPath:
            // '' (empty)  - representing the root directory
            // readme.txt
            // abc\def
            // abc\def\readme.txt

            // converting the naming convention
            virtualPath = UnderlayPathParser.ConvertDirectorySeparatorToOtherSystem(virtualPath, PathParser);

            // the contents of virtualPath:
            // / -- Prohibited
            // /abc -- Prohibited
            // '' (empty)  - representing the root directory
            // readme.txt
            // abc/def
            // abc/def/readme.txt
            if (PathParser.IsAbsolutePath(virtualPath, false))
            {
                throw new MapPathException($"The path \"{virtualPath}\" returned by MapPathPhysicalToVirtualImpl() is an absolute path.");
            }

            virtualPath = "/" + virtualPath;
            // Add "/" prefix on the virtual path

            // the examples of virtualPath:
            // /
            // /readme.txt
            // /abc/def
            // /abc/def/readme.txt

            // Check if the virtual path returned by MapPathPhysicalToVirtualImpl() is absolute path again
            virtualPath = PathParser.NormalizeDirectorySeparatorAndCheckIfAbsolutePath(virtualPath);

            virtualPath = PathParser.NormalizeUnixStylePathWithRemovingRelativeDirectoryElements(virtualPath);

            return(virtualPath);
        }
        public DirectoryPath ConfigPathStringToPhysicalDirectoryPath(string pathString)
        {
            pathString = pathString._NonNullTrim();

            if (pathString._IsEmpty())
            {
                throw new ArgumentNullException(nameof(pathString));
            }

            pathString = PathParser.NormalizeDirectorySeparator(pathString, true);

            if (PathParser.IsAbsolutePath(pathString))
            {
                return(pathString);
            }
            else
            {
                pathString = "/" + PathParser.Linux.NormalizeDirectorySeparator(pathString, true);

                string[] elements = PathParser.Linux.SplitAbsolutePathToElementsUnixStyle(pathString);

                string tmp = PathParser.Linux.BuildAbsolutePathStringFromElements(elements);

                tmp = PathParser.Linux.NormalizeDirectorySeparator(tmp, true);

                if (tmp[0] != '/')
                {
                    throw new ApplicationException("tmp[0] != '/'");
                }

                tmp = tmp.Substring(1);

                tmp = PathParser.Combine(Env.AppRootDir, tmp, true);

                return(tmp);
            }
        }
        public string MapPathVirtualToPhysical(string virtualPath)
        {
            if (virtualPath._IsEmpty())
            {
                return("");
            }

            // virtualPath must be UNIX-style absolute path
            // /
            // /abc/def
            // /abc/def/
            // /abc/def/readme.txt
            // /abc/def/../readme.txt
            // /abc/def/../../readme.txt
            // /abc/def/../../../readme.txt
            virtualPath = PathParser.NormalizeDirectorySeparatorAndCheckIfAbsolutePath(virtualPath);

            // remove any dangerous relative directory strings
            // /                              ----> / (unchanged)
            // /abc/def                       ----> /abc/def (unchanged)
            // /abc/def/                      ----> /abc/def (the last '/' is removed)
            // /abc/def/readme.txt            ----> /abc/def/readme.txt (unchanged)
            // /abc/def/../readme.txt         ----> /abc/readme.txt (normalized for security)
            // /abc/def/../../readme.txt      ----> /readme.txt (normalized for security)
            // /abc/def/../../../readme.txt   ----> /readme.txt (normalized for security)
            virtualPath = PathParser.NormalizeUnixStylePathWithRemovingRelativeDirectoryElements(virtualPath);

            // remove the first letter
            if (virtualPath.Length == 0 || virtualPath[0] != '/')
            {
                throw new MapPathException($"The normalized virtual path \"{virtualPath}\" does not an absolute path.");
            }

            virtualPath = virtualPath.Substring(1);

            // the contents of virtualPath:
            // '' (empty)  - representing the root directory
            // readme.txt
            // abc/def
            // abc/def/readme.txt

            // converting the naming convention
            virtualPath = PathParser.ConvertDirectorySeparatorToOtherSystem(virtualPath, UnderlayPathParser);

            // the contents of virtualPath:
            // '' (empty)  - representing the root directory
            // readme.txt
            // abc\def
            // abc\def\readme.txt

            // Make sure the path is not an absolute
            if (PathParser.IsAbsolutePath(virtualPath, true))
            {
                throw new MapPathException($"The virtualPath \"{virtualPath}\" must not be an absolute path here.");
            }

            // delegating to the derive class
            string physicalPath = MapPathVirtualToPhysicalImpl(virtualPath);

            // the contents of physicalPath:
            // c:\view_root
            // c:\view_root\readme.txt
            // c:\view_root\abc\def
            // c:\view_root\abc\def\readme.txt

            return(physicalPath);
        }