1/*
2 * Copyright 2008 the original author or authors.
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16package org.mockftpserver.fake.filesystem
17
18import java.io.File
19import java.io.IOException
20
21/**
22 * Implementation of the {@link FileSystem} interface that simulates a Microsoft
23 * Windows file system. The rules for file and directory names include:
24 * <ul>
25 *   <li>Filenames are case-insensitive (and normalized to lower-case)</li>
26 *   <li>Either forward slashes (/) or backward slashes (\) are valid path separators (but are normalized to '\')</li>
27 *   <li>An absolute path starts with a drive specifier (e.g. 'a:' or 'c:') followed
28 *   		by '\' or '/', or else if it starts with "\\"</li>
29 * </ul>
30 *
31 * @version $Revision: $ - $Date: $
32 *
33 * @author Chris Mair
34 */
35class FakeWindowsFileSystem extends AbstractFakeFileSystem {
36
37    public static final String SEPARATOR = "\\"
38    static final VALID_PATTERN = /\p{Alpha}\:(\\|(\\[^\\\:\*\?\<\>\|\"]+)+)/
39    static final LAN_PREFIX = "\\\\"
40
41    //-------------------------------------------------------------------------
42    // Abstract Method Implementations
43    //-------------------------------------------------------------------------
44
45    protected String getSeparator() {
46        return SEPARATOR
47    }
48
49    protected boolean isValidName(String path) {
50        // \/:*?"<>|
51        assert path != null
52        def standardized = path.replace("/", "\\")
53        return (standardized ==~ VALID_PATTERN) || standardized.startsWith(LAN_PREFIX)
54    }
55
56    /**
57     * Return true if the specified char is a separator character ('\' or '/')
58     * @param c - the character to test
59     * @return true if the specified char is a separator character ('\' or '/')
60     */
61    protected boolean isSeparator(char c) {
62        return c == '\\' || c == '/'
63    }
64
65    protected String componentsToPath(List components) {
66        if (components.size() == 1) {
67            def first = components[0]
68            if (first == "" || isRoot(first)) {
69                return first + this.separator
70            }
71        }
72        return components.join(this.separator)
73    }
74
75    protected boolean isRoot(String pathComponent) {
76        return pathComponent.contains(":")
77    }
78
79    /**
80     * Return the components of the specified path as a List. The components are normalized, and
81     * the returned List does not include path separator characters.
82     */
83    protected List normalizedComponents(String path) {
84        assert path != null
85        def p = path.replace("/", this.separator)
86
87        // TODO better way to do this
88        if (p == this.separator) {
89            return [""]
90        }
91
92        def parts = p.split("\\" + this.separator) as List
93        def result = []
94        parts.each { part ->
95            if (part == "..") {
96                result.remove(result.size()-1)
97            }
98            else if (part != ".") {
99                result << part
100            }
101        }
102        return result
103    }
104
105    /**
106     * Return true if the specified path designates an absolute file path. For Windows
107     * paths, a path is absolute if it starts with a drive specifier followed by
108     * '\' or '/', or if it starts with "\\".
109     *
110     * @param path - the path
111     * @return true if path is absolute, false otherwise
112     *
113     * @throws AssertionError - if path is null
114     */
115    boolean isAbsolute(String path) {
116        return isValidName(path)
117    }
118
119 }