Bug 1568860 - Part 1: Use PageStyle from the currently selected element in the fonts...
[gecko.git] / storage / FileSystemModule.cpp
blob1bf60920bb2d64a15ddb81903e2f40834951d41c
1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
2 * vim: sw=2 ts=2 et lcs=trail\:.,tab\:>~ :
3 * This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
7 #include "FileSystemModule.h"
9 #include "sqlite3.h"
10 #include "nsString.h"
11 #include "nsIDirectoryEnumerator.h"
12 #include "nsIFile.h"
14 namespace {
16 struct VirtualTableCursorBase {
17 VirtualTableCursorBase() { memset(&mBase, 0, sizeof(mBase)); }
19 sqlite3_vtab_cursor mBase;
22 struct VirtualTableCursor : public VirtualTableCursorBase {
23 public:
24 VirtualTableCursor() : mRowId(-1) { mCurrentFileName.SetIsVoid(true); }
26 const nsString& DirectoryPath() const { return mDirectoryPath; }
28 const nsString& CurrentFileName() const { return mCurrentFileName; }
30 int64_t RowId() const { return mRowId; }
32 nsresult Init(const nsAString& aPath);
33 nsresult NextFile();
35 private:
36 nsCOMPtr<nsIDirectoryEnumerator> mEntries;
38 nsString mDirectoryPath;
39 nsString mCurrentFileName;
41 int64_t mRowId;
44 nsresult VirtualTableCursor::Init(const nsAString& aPath) {
45 nsCOMPtr<nsIFile> directory = do_CreateInstance(NS_LOCAL_FILE_CONTRACTID);
46 NS_ENSURE_TRUE(directory, NS_ERROR_FAILURE);
48 nsresult rv = directory->InitWithPath(aPath);
49 NS_ENSURE_SUCCESS(rv, rv);
51 rv = directory->GetPath(mDirectoryPath);
52 NS_ENSURE_SUCCESS(rv, rv);
54 rv = directory->GetDirectoryEntries(getter_AddRefs(mEntries));
55 NS_ENSURE_SUCCESS(rv, rv);
57 rv = NextFile();
58 NS_ENSURE_SUCCESS(rv, rv);
60 return NS_OK;
63 nsresult VirtualTableCursor::NextFile() {
64 bool hasMore;
65 nsresult rv = mEntries->HasMoreElements(&hasMore);
66 NS_ENSURE_SUCCESS(rv, rv);
68 if (!hasMore) {
69 mCurrentFileName.SetIsVoid(true);
70 return NS_OK;
73 nsCOMPtr<nsISupports> entry;
74 rv = mEntries->GetNext(getter_AddRefs(entry));
75 NS_ENSURE_SUCCESS(rv, rv);
77 nsCOMPtr<nsIFile> file = do_QueryInterface(entry);
78 NS_ENSURE_TRUE(file, NS_ERROR_FAILURE);
80 rv = file->GetLeafName(mCurrentFileName);
81 NS_ENSURE_SUCCESS(rv, rv);
83 mRowId++;
85 return NS_OK;
88 int Connect(sqlite3* aDB, void* aAux, int aArgc, const char* const* aArgv,
89 sqlite3_vtab** aVtab, char** aErr) {
90 static const char virtualTableSchema[] =
91 "CREATE TABLE fs ("
92 "name TEXT, "
93 "path TEXT"
94 ")";
96 int rc = sqlite3_declare_vtab(aDB, virtualTableSchema);
97 if (rc != SQLITE_OK) {
98 return rc;
101 sqlite3_vtab* vt = new sqlite3_vtab();
102 memset(vt, 0, sizeof(*vt));
104 *aVtab = vt;
106 return SQLITE_OK;
109 int Disconnect(sqlite3_vtab* aVtab) {
110 delete aVtab;
112 return SQLITE_OK;
115 int BestIndex(sqlite3_vtab* aVtab, sqlite3_index_info* aInfo) {
116 // Here we specify what index constraints we want to handle. That is, there
117 // might be some columns with particular constraints in which we can help
118 // SQLite narrow down the result set.
120 // For example, take the "path = x" where x is a directory. In this case,
121 // we can narrow our search to just this directory instead of the entire file
122 // system. This can be a significant optimization. So, we want to handle that
123 // constraint. To do so, we would look for two specific input conditions:
125 // 1. aInfo->aConstraint[i].iColumn == 1
126 // 2. aInfo->aConstraint[i].op == SQLITE_INDEX_CONSTRAINT_EQ
128 // The first states that the path column is being used in one of the input
129 // constraints and the second states that the constraint involves the equal
130 // operator.
132 // An even more specific search would be for name='xxx', in which case we
133 // can limit the search to a single file, if it exists.
135 // What we have to do here is look for all of our index searches and select
136 // the narrowest. We can only pick one, so obviously we want the one that
137 // is the most specific, which leads to the smallest result set.
139 for (int i = 0; i < aInfo->nConstraint; i++) {
140 if (aInfo->aConstraint[i].iColumn == 1 && aInfo->aConstraint[i].usable) {
141 if (aInfo->aConstraint[i].op & SQLITE_INDEX_CONSTRAINT_EQ) {
142 aInfo->aConstraintUsage[i].argvIndex = 1;
144 break;
147 // TODO: handle single files (constrained also by the name column)
150 return SQLITE_OK;
153 int Open(sqlite3_vtab* aVtab, sqlite3_vtab_cursor** aCursor) {
154 VirtualTableCursor* cursor = new VirtualTableCursor();
156 *aCursor = reinterpret_cast<sqlite3_vtab_cursor*>(cursor);
158 return SQLITE_OK;
161 int Close(sqlite3_vtab_cursor* aCursor) {
162 VirtualTableCursor* cursor = reinterpret_cast<VirtualTableCursor*>(aCursor);
164 delete cursor;
166 return SQLITE_OK;
169 int Filter(sqlite3_vtab_cursor* aCursor, int aIdxNum, const char* aIdxStr,
170 int aArgc, sqlite3_value** aArgv) {
171 VirtualTableCursor* cursor = reinterpret_cast<VirtualTableCursor*>(aCursor);
173 if (aArgc <= 0) {
174 return SQLITE_OK;
177 const char16_t* value =
178 static_cast<const char16_t*>(::sqlite3_value_text16(aArgv[0]));
180 nsDependentString path(value,
181 ::sqlite3_value_bytes16(aArgv[0]) / sizeof(char16_t));
183 nsresult rv = cursor->Init(path);
184 NS_ENSURE_SUCCESS(rv, SQLITE_ERROR);
186 return SQLITE_OK;
189 int Next(sqlite3_vtab_cursor* aCursor) {
190 VirtualTableCursor* cursor = reinterpret_cast<VirtualTableCursor*>(aCursor);
192 nsresult rv = cursor->NextFile();
193 NS_ENSURE_SUCCESS(rv, SQLITE_ERROR);
195 return SQLITE_OK;
198 int Eof(sqlite3_vtab_cursor* aCursor) {
199 VirtualTableCursor* cursor = reinterpret_cast<VirtualTableCursor*>(aCursor);
200 return cursor->CurrentFileName().IsVoid() ? 1 : 0;
203 int Column(sqlite3_vtab_cursor* aCursor, sqlite3_context* aContext,
204 int aColumnIndex) {
205 VirtualTableCursor* cursor = reinterpret_cast<VirtualTableCursor*>(aCursor);
207 switch (aColumnIndex) {
208 // name
209 case 0: {
210 const nsString& name = cursor->CurrentFileName();
211 sqlite3_result_text16(aContext, name.get(),
212 name.Length() * sizeof(char16_t), SQLITE_TRANSIENT);
213 break;
216 // path
217 case 1: {
218 const nsString& path = cursor->DirectoryPath();
219 sqlite3_result_text16(aContext, path.get(),
220 path.Length() * sizeof(char16_t), SQLITE_TRANSIENT);
221 break;
223 default:
224 MOZ_ASSERT_UNREACHABLE("Unsupported column!");
227 return SQLITE_OK;
230 int RowId(sqlite3_vtab_cursor* aCursor, sqlite3_int64* aRowid) {
231 VirtualTableCursor* cursor = reinterpret_cast<VirtualTableCursor*>(aCursor);
233 *aRowid = cursor->RowId();
235 return SQLITE_OK;
238 } // namespace
240 namespace mozilla {
241 namespace storage {
243 int RegisterFileSystemModule(sqlite3* aDB, const char* aName) {
244 static sqlite3_module module = {
245 1, Connect, Connect, BestIndex, Disconnect, Disconnect, Open,
246 Close, Filter, Next, Eof, Column, RowId, nullptr,
247 nullptr, nullptr, nullptr, nullptr, nullptr, nullptr};
249 return sqlite3_create_module(aDB, aName, &module, nullptr);
252 } // namespace storage
253 } // namespace mozilla