| /*---------------------------------------------------------------------------* |
| * PANSIFileSystemImpl.c * |
| * * |
| * Copyright 2007, 2008 Nuance Communciations, Inc. * |
| * * |
| * Licensed under the Apache License, Version 2.0 (the 'License'); * |
| * you may not use this file except in compliance with the License. * |
| * * |
| * You may obtain a copy of the License at * |
| * http://www.apache.org/licenses/LICENSE-2.0 * |
| * * |
| * Unless required by applicable law or agreed to in writing, software * |
| * distributed under the License is distributed on an 'AS IS' BASIS, * |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * |
| * See the License for the specific language governing permissions and * |
| * limitations under the License. * |
| * * |
| *---------------------------------------------------------------------------*/ |
| |
| |
| #include "LCHAR.h" |
| #include "PFileSystemImpl.h" |
| #include "PANSIFileSystemImpl.h" |
| #include "PANSIFileImpl.h" |
| #include "plog.h" |
| #include "pmemory.h" |
| |
| //extern PFileSystem* PANSIFileSystemSingleton; |
| PFileSystem* PANSIFileSystemSingleton = (PFileSystem*)NULL; |
| |
| #define MTAG NULL |
| |
| |
| #ifdef USE_THREAD |
| /* Prototype of private function */ |
| PORTABLE_API ESR_ReturnCode PtrdFlush(); |
| #endif |
| |
| /** |
| * [file path, PFileSystem*] mapping. |
| */ |
| extern PHashTable* PFileSystemPathMap; |
| |
| |
| ESR_ReturnCode PANSIFileSystemCreate(void) |
| { |
| PANSIFileSystemImpl* impl; |
| ESR_ReturnCode rc; |
| |
| if (PANSIFileSystemSingleton != NULL) |
| return ESR_SUCCESS; |
| impl = NEW(PANSIFileSystemImpl, MTAG); |
| if (impl == NULL) |
| return ESR_OUT_OF_MEMORY; |
| impl->super.super.destroy = &PANSIFileSystemDestroyImpl; |
| impl->super.super.createPFile = &PANSIFileSystemCreatePFileImpl; |
| impl->super.addPath = &PANSIFileSystemAddPathImpl; |
| impl->super.removePath = &PANSIFileSystemRemovePathImpl; |
| impl->super.getcwd = &PANSIFileSystemGetcwdImpl; |
| impl->super.super.mkdir = &PANSIFileSystemMkdirImpl; |
| impl->super.super.chdir = &PANSIFileSystemChdirImpl; |
| |
| CHKLOG(rc, PHashTableCreate(NULL, MTAG, &impl->directoryMap)); |
| PANSIFileSystemSingleton = &impl->super.super; |
| return ESR_SUCCESS; |
| CLEANUP: |
| return rc; |
| } |
| |
| ESR_ReturnCode PANSIFileSystemDestroyImpl(PFileSystem* self) |
| { |
| PANSIFileSystemImpl* impl = (PANSIFileSystemImpl*) self; |
| PHashTableEntry* entry; |
| PHashTableEntry* oldEntry; |
| LCHAR* key; |
| LCHAR* value; |
| ESR_ReturnCode rc; |
| |
| if (impl->directoryMap != NULL) |
| { |
| CHKLOG(rc, PHashTableEntryGetFirst(impl->directoryMap, &entry)); |
| while (entry != NULL) |
| { |
| CHKLOG(rc, PHashTableEntryGetKeyValue(entry, (void **)&key, (void **)&value)); |
| oldEntry = entry; |
| CHKLOG(rc, PHashTableEntryAdvance(&entry)); |
| CHKLOG(rc, PHashTableEntryRemove(oldEntry)); |
| CHKLOG(rc, PHashTableRemoveValue(PFileSystemPathMap, key, NULL)); |
| FREE(key); |
| FREE(value); |
| } |
| CHKLOG(rc, PHashTableDestroy(impl->directoryMap)); |
| impl->directoryMap = NULL; |
| } |
| FREE(self); |
| return ESR_SUCCESS; |
| CLEANUP: |
| return rc; |
| } |
| |
| ESR_ReturnCode PANSIFileSystemAddPathImpl(PFileSystem* self, const LCHAR* virtualPath, const LCHAR* realPath) |
| { |
| PANSIFileSystemImpl* impl = (PANSIFileSystemImpl*) self; |
| ESR_BOOL exists; |
| LCHAR* key = NULL; |
| LCHAR* value = NULL; |
| ESR_ReturnCode rc; |
| size_t len; |
| |
| if (virtualPath == NULL || realPath == NULL) |
| { |
| rc = ESR_INVALID_ARGUMENT; |
| PLogError(ESR_rc2str(rc)); |
| goto CLEANUP; |
| } |
| |
| len = LSTRLEN(virtualPath) + 1; |
| if (virtualPath[LSTRLEN(virtualPath)-1] != L('/')) |
| ++len; |
| key = MALLOC(sizeof(LCHAR) * len, MTAG); |
| if (key == NULL) |
| { |
| rc = ESR_OUT_OF_MEMORY; |
| PLogError(ESR_rc2str(rc)); |
| goto CLEANUP; |
| } |
| LSTRCPY(key, virtualPath); |
| /* Make sure paths end with '/' */ |
| CHKLOG(rc, PFileSystemCanonicalSlashes(key)); |
| if (key[LSTRLEN(key)-1] != L('/')) |
| LSTRCAT(key, L("/")); |
| value = MALLOC(sizeof(LCHAR) * (LSTRLEN(realPath) + 1), MTAG); |
| if (value == NULL) |
| { |
| rc = ESR_OUT_OF_MEMORY; |
| PLogError(ESR_rc2str(rc)); |
| goto CLEANUP; |
| } |
| LSTRCPY(value, realPath); |
| |
| /* Make sure realPath is not an empty string */ |
| lstrtrim(value); |
| if (LSTRLEN(value) == 0) |
| { |
| FREE(value); |
| value = NULL; |
| rc = ESR_INVALID_ARGUMENT; |
| PLogError(L("%s: realPath cannot be empty"), ESR_rc2str(rc)); |
| goto CLEANUP; |
| } |
| |
| /* Make sure paths end with '/' */ |
| CHKLOG(rc, PFileSystemCanonicalSlashes(value)); |
| if (value[LSTRLEN(value)-1] != L('/')) |
| LSTRCAT(value, L("/")); |
| |
| CHKLOG(rc, PHashTableContainsKey(impl->directoryMap, key, &exists)); |
| if (exists) |
| { |
| LCHAR* oldValue; |
| |
| CHKLOG(rc, PHashTableGetValue(impl->directoryMap, key, (void **)&oldValue)); |
| if (LSTRCMP(oldValue, value) != 0) |
| { |
| rc = ESR_IDENTIFIER_COLLISION; |
| PLogError(ESR_rc2str(rc)); |
| goto CLEANUP; |
| } |
| } |
| CHKLOG(rc, PHashTablePutValue(impl->directoryMap, key, value, NULL)); |
| CHKLOG(rc, PHashTablePutValue(PFileSystemPathMap, key, self, NULL)); |
| return ESR_SUCCESS; |
| CLEANUP: |
| FREE(key); |
| FREE(value); |
| return rc; |
| } |
| |
| ESR_ReturnCode PANSIFileSystemRemovePathImpl(PFileSystem* self, const LCHAR* virtualPath) |
| { |
| PANSIFileSystemImpl* impl = (PANSIFileSystemImpl*) self; |
| LCHAR path[P_PATH_MAX]; |
| LCHAR* key; |
| LCHAR* value; |
| PHashTableEntry* entry; |
| ESR_ReturnCode rc; |
| |
| if (virtualPath == NULL) |
| { |
| rc = ESR_INVALID_ARGUMENT; |
| PLogError(ESR_rc2str(rc)); |
| goto CLEANUP; |
| } |
| /* Make sure paths end with '/' */ |
| LSTRCPY(path, virtualPath); |
| CHKLOG(rc, PFileSystemCanonicalSlashes(path)); |
| if (path[LSTRLEN(path)-1] != L('/')) |
| LSTRCAT(path, L("/")); |
| CHKLOG(rc, PHashTableGetEntry(impl->directoryMap, path, &entry)); |
| CHKLOG(rc, PHashTableEntryGetKeyValue(entry, (void **)&key, (void **)&value)); |
| CHKLOG(rc, PHashTableEntryRemove(entry)); |
| CHKLOG(rc, PHashTableRemoveValue(PFileSystemPathMap, key, NULL)); |
| FREE(key); |
| FREE(value); |
| return ESR_SUCCESS; |
| CLEANUP: |
| return rc; |
| } |
| |
| ESR_ReturnCode PANSIFileSystemGetRealPathImpl(PFileSystem* self, LCHAR* path, size_t* len) |
| { |
| PANSIFileSystemImpl* impl = (PANSIFileSystemImpl*) self; |
| PHashTableEntry* entry; |
| LCHAR* key; |
| LCHAR* value; |
| LCHAR* bestKey = NULL; |
| LCHAR* bestValue = NULL; |
| ESR_BOOL isAbsolute; |
| ESR_ReturnCode rc; |
| |
| CHKLOG(rc, PFileSystemGetAbsolutePath(path, len)); |
| CHKLOG(rc, PHashTableEntryGetFirst(impl->directoryMap, &entry)); |
| while (entry != NULL) |
| { |
| CHKLOG(rc, PHashTableEntryGetKeyValue(entry, (void**)&key, (void**)&value)); |
| if (LSTRNCMP(path, key, LSTRLEN(key)) == 0) |
| { |
| /* File-system handles file path */ |
| if (bestKey == NULL || LSTRLEN(key) > LSTRLEN(bestKey)) |
| { |
| /* Found a better match -- the new key is a subdirectory of the previous bestKey */ |
| bestKey = key; |
| bestValue = value; |
| } |
| } |
| CHKLOG(rc, PHashTableEntryAdvance(&entry)); |
| } |
| if (bestKey == NULL) |
| { |
| rc = ESR_INVALID_STATE; |
| PLogError(L("PANSIFileSystem does not handle the specified path: %s"), path); |
| goto CLEANUP; |
| } |
| |
| if (LSTRLEN(bestValue) + 1 > *len) |
| { |
| *len = LSTRLEN(bestValue) + 1; |
| rc = ESR_BUFFER_OVERFLOW; |
| PLogError(ESR_rc2str(rc)); |
| goto CLEANUP; |
| } |
| /* Delete the virtual-path */ |
| LSTRCPY(path, path + LSTRLEN(bestKey)); |
| |
| CHKLOG(rc, PFileSystemIsAbsolutePath(path, &isAbsolute)); |
| if (LSTRCMP(bestValue, L("/")) == 0 && isAbsolute) |
| { |
| /* do nothing */ |
| } |
| else |
| { |
| /* Insert the key-path */ |
| CHKLOG(rc, lstrinsert(bestValue, path, 0, len)); |
| } |
| return ESR_SUCCESS; |
| CLEANUP: |
| return rc; |
| } |
| |
| ESR_ReturnCode PANSIFileSystemCreatePFileImpl(PFileSystem* self, const LCHAR* path, ESR_BOOL littleEndian, PFile** file) |
| { |
| LCHAR realPath[P_PATH_MAX]; |
| size_t len; |
| ESR_ReturnCode rc; |
| |
| LSTRCPY(realPath, path); |
| len = P_PATH_MAX; |
| CHKLOG(rc, PANSIFileSystemGetRealPathImpl(self, realPath, &len)); |
| return PANSIFileCreateImpl(realPath, littleEndian, file); |
| CLEANUP: |
| return rc; |
| } |
| |
| ESR_ReturnCode PANSIFileSystemSetDefault(ESR_BOOL isDefault) |
| { |
| PANSIFileSystemImpl* impl = (PANSIFileSystemImpl*) PANSIFileSystemSingleton; |
| ESR_BOOL exists; |
| LCHAR* key = NULL; |
| LCHAR* value = NULL; |
| PHashTableEntry* entry; |
| ESR_ReturnCode rc; |
| |
| if (isDefault) |
| { |
| |
| key = MALLOC(sizeof(LCHAR), MTAG); |
| if (key == NULL) |
| { |
| rc = ESR_OUT_OF_MEMORY; |
| PLogError(ESR_rc2str(rc)); |
| goto CLEANUP; |
| } |
| LSTRCPY(key, L("")); |
| value = MALLOC(sizeof(LCHAR), MTAG); |
| if (value == NULL) |
| { |
| rc = ESR_OUT_OF_MEMORY; |
| PLogError(ESR_rc2str(rc)); |
| goto CLEANUP; |
| } |
| LSTRCPY(value, L("")); |
| |
| CHKLOG(rc, PHashTableContainsKey(impl->directoryMap, key, &exists)); |
| if (exists) |
| { |
| LCHAR* key; |
| LCHAR* value; |
| |
| CHKLOG(rc, PHashTableGetEntry(impl->directoryMap, L(""), &entry)); |
| CHKLOG(rc, PHashTableEntryGetKeyValue(entry, (void **)&key, (void **)&value)); |
| CHKLOG(rc, PHashTableEntryRemove(entry)); |
| CHKLOG(rc, PHashTableRemoveValue(PFileSystemPathMap, key, NULL)); |
| FREE(key); |
| FREE(value); |
| } |
| CHKLOG(rc, PHashTablePutValue(impl->directoryMap, key, value, NULL)); |
| CHKLOG(rc, PHashTablePutValue(PFileSystemPathMap, key, PANSIFileSystemSingleton, NULL)); |
| |
| /* Set virtual current working directory to native current working directory */ |
| } |
| else |
| { |
| CHKLOG(rc, PHashTableContainsKey(impl->directoryMap, L(""), &exists)); |
| if (exists) |
| { |
| LCHAR* key; |
| LCHAR* value; |
| |
| CHKLOG(rc, PHashTableGetEntry(impl->directoryMap, L(""), &entry)); |
| CHKLOG(rc, PHashTableEntryGetKeyValue(entry, (void **)&key, (void **)&value)); |
| |
| CHKLOG(rc, PHashTableContainsKey(PFileSystemPathMap, L(""), &exists)); |
| if (exists) |
| { |
| LCHAR* key; |
| PFileSystem* value; |
| PHashTableEntry* entry; |
| |
| CHKLOG(rc, PHashTableGetEntry(PFileSystemPathMap, L(""), &entry)); |
| CHKLOG(rc, PHashTableEntryGetKeyValue(entry, (void **)&key, (void **)&value)); |
| if (value == PANSIFileSystemSingleton) |
| CHKLOG(rc, PHashTableEntryRemove(entry)); |
| } |
| |
| CHKLOG(rc, PHashTableEntryRemove(entry)); |
| FREE(key); |
| FREE(value); |
| } |
| } |
| return ESR_SUCCESS; |
| CLEANUP: |
| FREE(key); |
| FREE(value); |
| return rc; |
| } |