1/*
2 * Copyright 2013, Ingo Weinhold, ingo_weinhold@gmx.de.
3 * Distributed under the terms of the MIT License.
4 */
5#ifndef FS_UTILS_H
6#define FS_UTILS_H
7
8
9#include <new>
10
11#include <String.h>
12
13#include <EntryOperationEngineBase.h>
14
15
16class BDirectory;
17class BFile;
18class BPositionIO;
19class BSymLink;
20
21
22class FSUtils {
23public:
24	typedef ::BPrivate::BEntryOperationEngineBase::Entry Entry;
25
26public:
27	struct RelativePath {
28		RelativePath(const char* component1 = NULL,
29			const char* component2 = NULL, const char* component3 = NULL)
30			:
31			fComponentCount(kMaxComponentCount)
32		{
33			fComponents[0] = component1;
34			fComponents[1] = component2;
35			fComponents[2] = component3;
36
37			for (size_t i = 0; i < kMaxComponentCount; i++) {
38				if (fComponents[i] == NULL) {
39					fComponentCount = i;
40					break;
41				}
42			}
43		}
44
45		bool IsEmpty() const
46		{
47			return fComponentCount == 0;
48		}
49
50		RelativePath HeadPath(size_t componentsToDropCount = 1)
51		{
52			RelativePath result;
53			if (componentsToDropCount < fComponentCount) {
54				result.fComponentCount
55					= fComponentCount - componentsToDropCount;
56				for (size_t i = 0; i < result.fComponentCount; i++)
57					result.fComponents[i] = fComponents[i];
58			}
59
60			return result;
61		}
62
63		const char* LastComponent() const
64		{
65			return fComponentCount > 0
66				? fComponents[fComponentCount - 1] : NULL;
67		}
68
69		BString ToString() const
70		{
71			if (fComponentCount == 0)
72				return BString();
73
74			size_t length = fComponentCount - 1;
75			for (size_t i = 0; i < fComponentCount; i++)
76				length += strlen(fComponents[i]);
77
78			BString result;
79			char* buffer = result.LockBuffer(length + 1);
80			if (buffer == NULL)
81				return BString();
82
83			for (size_t i = 0; i < fComponentCount; i++) {
84				if (i > 0) {
85					*buffer = '/';
86					buffer++;
87				}
88				strcpy(buffer, fComponents[i]);
89				buffer += strlen(buffer);
90			}
91
92			return result.UnlockBuffer();
93		}
94
95	private:
96		static const size_t	kMaxComponentCount = 3;
97
98		const char*	fComponents[kMaxComponentCount];
99		size_t		fComponentCount;
100	};
101
102	// throwing std::bad_alloc()
103	class Path {
104	public:
105		Path(const char* path)
106			:
107			fPath(path)
108		{
109			if (fPath.IsEmpty()) {
110				if (path[0] != '\0')
111					throw std::bad_alloc();
112			} else {
113				// remove duplicate '/'s
114				char* buffer = fPath.LockBuffer(fPath.Length());
115				int32 k = 0;
116				for (int32 i = 0; buffer[i] != '\0'; i++) {
117					if (buffer[i] == '/' && k > 0 && buffer[k - 1] == '/')
118						continue;
119					buffer[k++] = buffer[i];
120				}
121
122				// remove trailing '/'
123				if (k > 1 && buffer[k - 1] == '/')
124					k--;
125
126				fPath.LockBuffer(k);
127			}
128		}
129
130		Path& AppendComponent(const char* component)
131		{
132			if (fPath.IsEmpty()) {
133				fPath = component;
134				if (fPath.IsEmpty() && component[0] != '\0')
135					throw std::bad_alloc();
136			} else {
137				int32 length = fPath.Length();
138				if (fPath[length - 1] != '/') {
139					fPath += '/';
140					if (++length != fPath.Length())
141						throw std::bad_alloc();
142				}
143
144				fPath += component;
145				if (fPath.Length() <= length)
146					throw std::bad_alloc();
147			}
148
149			return *this;
150		}
151
152		Path& RemoveLastComponent()
153		{
154			int32 index = fPath.FindLast('/');
155			if (index < 0 || (index == 0 && fPath.Length() == 1))
156				fPath.Truncate(0);
157			else if (index == 0)
158				fPath.Truncate(1);
159			else
160				fPath.Truncate(index);
161			return *this;
162		}
163
164		const char* Leaf() const
165		{
166			int32 index = fPath.FindLast('/');
167			if (index < 0 || (index == 0 && fPath.Length() == 1))
168				return fPath.String();
169			return fPath.String() + index + 1;
170		}
171
172		const BString ToString() const
173		{
174			return fPath;
175		}
176
177		const char* ToCString() const
178		{
179			return fPath.String();
180		}
181
182		operator const BString&() const
183		{
184			return fPath;
185		}
186
187		operator const char*() const
188		{
189			return fPath;
190		}
191
192	private:
193		BString	fPath;
194	};
195
196public:
197	static	BString				ShellEscapeString(const BString& string);
198									// throw std::bad_alloc
199
200	static	status_t			OpenSubDirectory(
201									const BDirectory& baseDirectory,
202									const RelativePath& path, bool create,
203									BDirectory& _directory);
204
205	static	status_t			CompareFileContent(const Entry& entry1,
206									const Entry& entry2, bool& _equal);
207	static	status_t			CompareFileContent(BPositionIO& content1,
208									BPositionIO& content2, bool& _equal);
209
210	static	status_t			CompareSymLinks(const Entry& entry1,
211									const Entry& entry2, bool& _equal);
212	static	status_t			CompareSymLinks(BSymLink& symLink1,
213									BSymLink& symLink2, bool& _equal);
214
215	static	status_t			ExtractPackageContent(const Entry& packageEntry,
216									const char* contentPath,
217									const Entry& targetDirectoryEntry);
218	static	status_t			ExtractPackageContent(const char* packagePath,
219									const char* contentPath,
220									const char* targetDirectoryPath);
221
222private:
223	static	status_t			_OpenFile(const Entry& entry, BFile& file);
224	static	status_t			_OpenSymLink(const Entry& entry,
225									BSymLink& symLink);
226};
227
228
229
230#endif	// FS_UTILS_H
231