1/*---------------------------------------------------------------------------* 2 * PANSIFileSystemImpl.c * 3 * * 4 * Copyright 2007, 2008 Nuance Communciations, Inc. * 5 * * 6 * Licensed under the Apache License, Version 2.0 (the 'License'); * 7 * you may not use this file except in compliance with the License. * 8 * * 9 * You may obtain a copy of the License at * 10 * http://www.apache.org/licenses/LICENSE-2.0 * 11 * * 12 * Unless required by applicable law or agreed to in writing, software * 13 * distributed under the License is distributed on an 'AS IS' BASIS, * 14 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * 15 * See the License for the specific language governing permissions and * 16 * limitations under the License. * 17 * * 18 *---------------------------------------------------------------------------*/ 19 20 21#include "LCHAR.h" 22#include "PFileSystemImpl.h" 23#include "PANSIFileSystemImpl.h" 24#include "PANSIFileImpl.h" 25#include "plog.h" 26#include "pmemory.h" 27 28//extern PFileSystem* PANSIFileSystemSingleton; 29PFileSystem* PANSIFileSystemSingleton = (PFileSystem*)NULL; 30 31#define MTAG NULL 32 33 34#ifdef USE_THREAD 35/* Prototype of private function */ 36PORTABLE_API ESR_ReturnCode PtrdFlush(); 37#endif 38 39/** 40 * [file path, PFileSystem*] mapping. 41 */ 42extern PHashTable* PFileSystemPathMap; 43 44 45ESR_ReturnCode PANSIFileSystemCreate(void) 46{ 47 PANSIFileSystemImpl* impl; 48 ESR_ReturnCode rc; 49 50 if (PANSIFileSystemSingleton != NULL) 51 return ESR_SUCCESS; 52 impl = NEW(PANSIFileSystemImpl, MTAG); 53 if (impl == NULL) 54 return ESR_OUT_OF_MEMORY; 55 impl->super.super.destroy = &PANSIFileSystemDestroyImpl; 56 impl->super.super.createPFile = &PANSIFileSystemCreatePFileImpl; 57 impl->super.addPath = &PANSIFileSystemAddPathImpl; 58 impl->super.removePath = &PANSIFileSystemRemovePathImpl; 59 impl->super.getcwd = &PANSIFileSystemGetcwdImpl; 60 impl->super.super.mkdir = &PANSIFileSystemMkdirImpl; 61 impl->super.super.chdir = &PANSIFileSystemChdirImpl; 62 63 CHKLOG(rc, PHashTableCreate(NULL, MTAG, &impl->directoryMap)); 64 PANSIFileSystemSingleton = &impl->super.super; 65 return ESR_SUCCESS; 66CLEANUP: 67 return rc; 68} 69 70ESR_ReturnCode PANSIFileSystemDestroyImpl(PFileSystem* self) 71{ 72 PANSIFileSystemImpl* impl = (PANSIFileSystemImpl*) self; 73 PHashTableEntry* entry; 74 PHashTableEntry* oldEntry; 75 LCHAR* key; 76 LCHAR* value; 77 ESR_ReturnCode rc; 78 79 if (impl->directoryMap != NULL) 80 { 81 CHKLOG(rc, PHashTableEntryGetFirst(impl->directoryMap, &entry)); 82 while (entry != NULL) 83 { 84 CHKLOG(rc, PHashTableEntryGetKeyValue(entry, (void **)&key, (void **)&value)); 85 oldEntry = entry; 86 CHKLOG(rc, PHashTableEntryAdvance(&entry)); 87 CHKLOG(rc, PHashTableEntryRemove(oldEntry)); 88 CHKLOG(rc, PHashTableRemoveValue(PFileSystemPathMap, key, NULL)); 89 FREE(key); 90 FREE(value); 91 } 92 CHKLOG(rc, PHashTableDestroy(impl->directoryMap)); 93 impl->directoryMap = NULL; 94 } 95 FREE(self); 96 return ESR_SUCCESS; 97CLEANUP: 98 return rc; 99} 100 101ESR_ReturnCode PANSIFileSystemAddPathImpl(PFileSystem* self, const LCHAR* virtualPath, const LCHAR* realPath) 102{ 103 PANSIFileSystemImpl* impl = (PANSIFileSystemImpl*) self; 104 ESR_BOOL exists; 105 LCHAR* key = NULL; 106 LCHAR* value = NULL; 107 ESR_ReturnCode rc; 108 size_t len; 109 110 if (virtualPath == NULL || realPath == NULL) 111 { 112 rc = ESR_INVALID_ARGUMENT; 113 PLogError(ESR_rc2str(rc)); 114 goto CLEANUP; 115 } 116 117 len = LSTRLEN(virtualPath) + 1; 118 if (virtualPath[LSTRLEN(virtualPath)-1] != L('/')) 119 ++len; 120 key = MALLOC(sizeof(LCHAR) * len, MTAG); 121 if (key == NULL) 122 { 123 rc = ESR_OUT_OF_MEMORY; 124 PLogError(ESR_rc2str(rc)); 125 goto CLEANUP; 126 } 127 LSTRCPY(key, virtualPath); 128 /* Make sure paths end with '/' */ 129 CHKLOG(rc, PFileSystemCanonicalSlashes(key)); 130 if (key[LSTRLEN(key)-1] != L('/')) 131 LSTRCAT(key, L("/")); 132 value = MALLOC(sizeof(LCHAR) * (LSTRLEN(realPath) + 1), MTAG); 133 if (value == NULL) 134 { 135 rc = ESR_OUT_OF_MEMORY; 136 PLogError(ESR_rc2str(rc)); 137 goto CLEANUP; 138 } 139 LSTRCPY(value, realPath); 140 141 /* Make sure realPath is not an empty string */ 142 lstrtrim(value); 143 if (LSTRLEN(value) == 0) 144 { 145 FREE(value); 146 value = NULL; 147 rc = ESR_INVALID_ARGUMENT; 148 PLogError(L("%s: realPath cannot be empty"), ESR_rc2str(rc)); 149 goto CLEANUP; 150 } 151 152 /* Make sure paths end with '/' */ 153 CHKLOG(rc, PFileSystemCanonicalSlashes(value)); 154 if (value[LSTRLEN(value)-1] != L('/')) 155 LSTRCAT(value, L("/")); 156 157 CHKLOG(rc, PHashTableContainsKey(impl->directoryMap, key, &exists)); 158 if (exists) 159 { 160 LCHAR* oldValue; 161 162 CHKLOG(rc, PHashTableGetValue(impl->directoryMap, key, (void **)&oldValue)); 163 if (LSTRCMP(oldValue, value) != 0) 164 { 165 rc = ESR_IDENTIFIER_COLLISION; 166 PLogError(ESR_rc2str(rc)); 167 goto CLEANUP; 168 } 169 } 170 CHKLOG(rc, PHashTablePutValue(impl->directoryMap, key, value, NULL)); 171 CHKLOG(rc, PHashTablePutValue(PFileSystemPathMap, key, self, NULL)); 172 return ESR_SUCCESS; 173CLEANUP: 174 FREE(key); 175 FREE(value); 176 return rc; 177} 178 179ESR_ReturnCode PANSIFileSystemRemovePathImpl(PFileSystem* self, const LCHAR* virtualPath) 180{ 181 PANSIFileSystemImpl* impl = (PANSIFileSystemImpl*) self; 182 LCHAR path[P_PATH_MAX]; 183 LCHAR* key; 184 LCHAR* value; 185 PHashTableEntry* entry; 186 ESR_ReturnCode rc; 187 188 if (virtualPath == NULL) 189 { 190 rc = ESR_INVALID_ARGUMENT; 191 PLogError(ESR_rc2str(rc)); 192 goto CLEANUP; 193 } 194 /* Make sure paths end with '/' */ 195 LSTRCPY(path, virtualPath); 196 CHKLOG(rc, PFileSystemCanonicalSlashes(path)); 197 if (path[LSTRLEN(path)-1] != L('/')) 198 LSTRCAT(path, L("/")); 199 CHKLOG(rc, PHashTableGetEntry(impl->directoryMap, path, &entry)); 200 CHKLOG(rc, PHashTableEntryGetKeyValue(entry, (void **)&key, (void **)&value)); 201 CHKLOG(rc, PHashTableEntryRemove(entry)); 202 CHKLOG(rc, PHashTableRemoveValue(PFileSystemPathMap, key, NULL)); 203 FREE(key); 204 FREE(value); 205 return ESR_SUCCESS; 206CLEANUP: 207 return rc; 208} 209 210ESR_ReturnCode PANSIFileSystemGetRealPathImpl(PFileSystem* self, LCHAR* path, size_t* len) 211{ 212 PANSIFileSystemImpl* impl = (PANSIFileSystemImpl*) self; 213 PHashTableEntry* entry; 214 LCHAR* key; 215 LCHAR* value; 216 LCHAR* bestKey = NULL; 217 LCHAR* bestValue = NULL; 218 ESR_BOOL isAbsolute; 219 ESR_ReturnCode rc; 220 221 CHKLOG(rc, PFileSystemGetAbsolutePath(path, len)); 222 CHKLOG(rc, PHashTableEntryGetFirst(impl->directoryMap, &entry)); 223 while (entry != NULL) 224 { 225 CHKLOG(rc, PHashTableEntryGetKeyValue(entry, (void**)&key, (void**)&value)); 226 if (LSTRNCMP(path, key, LSTRLEN(key)) == 0) 227 { 228 /* File-system handles file path */ 229 if (bestKey == NULL || LSTRLEN(key) > LSTRLEN(bestKey)) 230 { 231 /* Found a better match -- the new key is a subdirectory of the previous bestKey */ 232 bestKey = key; 233 bestValue = value; 234 } 235 } 236 CHKLOG(rc, PHashTableEntryAdvance(&entry)); 237 } 238 if (bestKey == NULL) 239 { 240 rc = ESR_INVALID_STATE; 241 PLogError(L("PANSIFileSystem does not handle the specified path: %s"), path); 242 goto CLEANUP; 243 } 244 245 if (LSTRLEN(bestValue) + 1 > *len) 246 { 247 *len = LSTRLEN(bestValue) + 1; 248 rc = ESR_BUFFER_OVERFLOW; 249 PLogError(ESR_rc2str(rc)); 250 goto CLEANUP; 251 } 252 /* Delete the virtual-path */ 253 LSTRCPY(path, path + LSTRLEN(bestKey)); 254 255 CHKLOG(rc, PFileSystemIsAbsolutePath(path, &isAbsolute)); 256 if (LSTRCMP(bestValue, L("/")) == 0 && isAbsolute) 257 { 258 /* do nothing */ 259 } 260 else 261 { 262 /* Insert the key-path */ 263 CHKLOG(rc, lstrinsert(bestValue, path, 0, len)); 264 } 265 return ESR_SUCCESS; 266CLEANUP: 267 return rc; 268} 269 270ESR_ReturnCode PANSIFileSystemCreatePFileImpl(PFileSystem* self, const LCHAR* path, ESR_BOOL littleEndian, PFile** file) 271{ 272 LCHAR realPath[P_PATH_MAX]; 273 size_t len; 274 ESR_ReturnCode rc; 275 276 LSTRCPY(realPath, path); 277 len = P_PATH_MAX; 278 CHKLOG(rc, PANSIFileSystemGetRealPathImpl(self, realPath, &len)); 279 return PANSIFileCreateImpl(realPath, littleEndian, file); 280CLEANUP: 281 return rc; 282} 283 284ESR_ReturnCode PANSIFileSystemSetDefault(ESR_BOOL isDefault) 285{ 286 PANSIFileSystemImpl* impl = (PANSIFileSystemImpl*) PANSIFileSystemSingleton; 287 ESR_BOOL exists; 288 LCHAR* key = NULL; 289 LCHAR* value = NULL; 290 PHashTableEntry* entry; 291 ESR_ReturnCode rc; 292 293 if (isDefault) 294 { 295 296 key = MALLOC(sizeof(LCHAR), MTAG); 297 if (key == NULL) 298 { 299 rc = ESR_OUT_OF_MEMORY; 300 PLogError(ESR_rc2str(rc)); 301 goto CLEANUP; 302 } 303 LSTRCPY(key, L("")); 304 value = MALLOC(sizeof(LCHAR), MTAG); 305 if (value == NULL) 306 { 307 rc = ESR_OUT_OF_MEMORY; 308 PLogError(ESR_rc2str(rc)); 309 goto CLEANUP; 310 } 311 LSTRCPY(value, L("")); 312 313 CHKLOG(rc, PHashTableContainsKey(impl->directoryMap, key, &exists)); 314 if (exists) 315 { 316 LCHAR* key; 317 LCHAR* value; 318 319 CHKLOG(rc, PHashTableGetEntry(impl->directoryMap, L(""), &entry)); 320 CHKLOG(rc, PHashTableEntryGetKeyValue(entry, (void **)&key, (void **)&value)); 321 CHKLOG(rc, PHashTableEntryRemove(entry)); 322 CHKLOG(rc, PHashTableRemoveValue(PFileSystemPathMap, key, NULL)); 323 FREE(key); 324 FREE(value); 325 } 326 CHKLOG(rc, PHashTablePutValue(impl->directoryMap, key, value, NULL)); 327 CHKLOG(rc, PHashTablePutValue(PFileSystemPathMap, key, PANSIFileSystemSingleton, NULL)); 328 329 /* Set virtual current working directory to native current working directory */ 330 } 331 else 332 { 333 CHKLOG(rc, PHashTableContainsKey(impl->directoryMap, L(""), &exists)); 334 if (exists) 335 { 336 LCHAR* key; 337 LCHAR* value; 338 339 CHKLOG(rc, PHashTableGetEntry(impl->directoryMap, L(""), &entry)); 340 CHKLOG(rc, PHashTableEntryGetKeyValue(entry, (void **)&key, (void **)&value)); 341 342 CHKLOG(rc, PHashTableContainsKey(PFileSystemPathMap, L(""), &exists)); 343 if (exists) 344 { 345 LCHAR* key; 346 PFileSystem* value; 347 PHashTableEntry* entry; 348 349 CHKLOG(rc, PHashTableGetEntry(PFileSystemPathMap, L(""), &entry)); 350 CHKLOG(rc, PHashTableEntryGetKeyValue(entry, (void **)&key, (void **)&value)); 351 if (value == PANSIFileSystemSingleton) 352 CHKLOG(rc, PHashTableEntryRemove(entry)); 353 } 354 355 CHKLOG(rc, PHashTableEntryRemove(entry)); 356 FREE(key); 357 FREE(value); 358 } 359 } 360 return ESR_SUCCESS; 361CLEANUP: 362 FREE(key); 363 FREE(value); 364 return rc; 365} 366