1 /*
2  * Hunt - A high-level D Programming Language Web framework that encourages rapid development and clean, pragmatic design.
3  *
4  * Copyright (C) 2015-2019, HuntLabs
5  *
6  * Website: https://www.huntlabs.net/
7  *
8  * Licensed under the Apache-2.0 License.
9  *
10  */
11 
12 module hunt.framework.file.File;
13 
14 import hunt.framework.file.Exceptions;
15 import hunt.framework.Simplify;
16 import hunt.framework.util.String;
17 
18 import std.path : dirName, buildPath;
19 import std.file : getSize, rename, isFile, isDir, exists;
20 import std.format;
21 
22 class File
23 {
24     private string _path;
25 
26     /**
27      * Constructs a new file from the given path.
28      *
29      * @param string $path      The path to the file
30      * @param bool   $checkPath Whether to check the path or not
31      *
32      * @throws FileNotFoundException If the given path is not a file
33      */
34     public this(string path, bool checkPath = true)
35     {
36         if (checkPath && isFile(path)) {
37             throw new FileNotFoundException(path);
38         }
39         
40         this._path = buildPath(APP_PATH, path);
41     }
42 
43     public string path()
44     {
45         return this._path;
46     }
47 
48     public long size()
49     {
50         return getSize(this._path);
51     }
52 
53     /**
54      * Returns the extension based on the mime type.
55      *
56      * If the mime type is unknown, returns null.
57      *
58      * This method uses the mime type as guessed by getMimeType()
59      * to guess the file extension.
60      *
61      * @return string|null The guessed extension or null if it cannot be guessed
62      *
63      * @see MimeTypes
64      * @see getMimeType()
65      */
66     public string extension()
67     {
68         // return MimeTypes::getDefault().getExtensions(this.getMimeType())[0] ?? null;
69         return null;
70     }
71 
72     /**
73      * Returns the mime type of the file.
74      *
75      * The mime type is guessed using a MimeTypeGuesserInterface instance,
76      * which uses finfo_file() then the "file" system binary,
77      * depending on which of those are available.
78      *
79      * @return string|null The guessed mime type (e.g. "application/pdf")
80      *
81      * @see MimeTypes
82      */
83     public string mimeType()
84     {
85         return getMimeTypeByFilename(this.path());
86     }
87 
88     /**
89      * Moves the file to a new location.
90      *
91      * @param string $path The file realpath
92      *
93      * @return self A File object representing the new file
94      *
95      * @throws FileException if the target file could not be created
96      */
97     public bool move(string path)
98     {
99         string target = this.getTargetFile(path);
100         
101         // error to throw FileException
102         rename(this.path(), target);
103 
104         version (Posix)
105         {
106             import std.exception : assertNotThrown;
107             import std.conv : octal;
108             import std.file : setAttributes;
109 
110             assertNotThrown!FileException(target.setAttributes(octal!644));
111         }
112         
113         return true;
114     }
115 
116     protected string getTargetFile(string path)
117     {
118         string target = buildPath(APP_PATH, path);
119         // if (isDir(target)) {
120         //     throw new FileException(format("Unable to create the \"%s\" directory.", target));
121         // }
122 
123         if (exists(target))
124         {
125             throw new FileException(format("The file or directory \"%s\" exists.", target));
126         }
127 
128         return target;
129     }
130 
131     /**
132      * Returns locale independent base name of the given path.
133      *
134      * @param string $name The new file name
135      *
136      * @return string containing
137      */
138     protected string getName(string name = null)
139     {
140         import std.string : lastIndexOf, replace;
141 
142         string originalName;
143 
144         if (name.length == 0)
145         {
146             originalName = this._path;
147         }
148         else
149         {
150             originalName = name;
151         }
152 
153         originalName = originalName.replace("\\", "/");
154         ptrdiff_t index = lastIndexOf(originalName, '/');
155         if(index>=0) {
156             originalName = originalName[index..$];
157         }
158 
159         return originalName;
160     }
161 }