diff options
Diffstat (limited to 'portable/src/PANSIFileSystemImpl.c')
-rw-r--r-- | portable/src/PANSIFileSystemImpl.c | 365 |
1 files changed, 365 insertions, 0 deletions
diff --git a/portable/src/PANSIFileSystemImpl.c b/portable/src/PANSIFileSystemImpl.c new file mode 100644 index 0000000..cbe74b3 --- /dev/null +++ b/portable/src/PANSIFileSystemImpl.c @@ -0,0 +1,365 @@ +/*---------------------------------------------------------------------------* + * 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; +} |