nuclear@3: /************************************************************************************ nuclear@3: nuclear@3: Filename : OVR_String_PathUtil.cpp nuclear@3: Content : String filename/url helper function nuclear@3: Created : September 19, 2012 nuclear@3: Notes : nuclear@3: nuclear@3: Copyright : Copyright 2012 Oculus VR, Inc. All Rights reserved. nuclear@3: nuclear@3: Use of this software is subject to the terms of the Oculus license nuclear@3: agreement provided at the time of installation or download, or which nuclear@3: otherwise accompanies this software in either electronic or hard copy form. nuclear@3: nuclear@3: ************************************************************************************/ nuclear@3: nuclear@3: #include "OVR_String.h" nuclear@3: #include "OVR_UTF8Util.h" nuclear@3: nuclear@3: namespace OVR { nuclear@3: nuclear@3: //-------------------------------------------------------------------- nuclear@3: // ***** Path-Scanner helper function nuclear@3: nuclear@3: // Scans file path finding filename start and extension start, fills in their addess. nuclear@3: void ScanFilePath(const char* url, const char** pfilename, const char** pext) nuclear@3: { nuclear@3: const char* urlStart = url; nuclear@3: const char *filename = 0; nuclear@3: const char *lastDot = 0; nuclear@3: nuclear@3: UInt32 charVal = UTF8Util::DecodeNextChar(&url); nuclear@3: nuclear@3: while (charVal != 0) nuclear@3: { nuclear@3: if ((charVal == '/') || (charVal == '\\')) nuclear@3: { nuclear@3: filename = url; nuclear@3: lastDot = 0; nuclear@3: } nuclear@3: else if (charVal == '.') nuclear@3: { nuclear@3: lastDot = url - 1; nuclear@3: } nuclear@3: nuclear@3: charVal = UTF8Util::DecodeNextChar(&url); nuclear@3: } nuclear@3: nuclear@3: if (pfilename) nuclear@3: { nuclear@3: // It was a naked filename nuclear@3: if (urlStart && (*urlStart != '.') && *urlStart) nuclear@3: *pfilename = urlStart; nuclear@3: else nuclear@3: *pfilename = filename; nuclear@3: } nuclear@3: nuclear@3: if (pext) nuclear@3: { nuclear@3: *pext = lastDot; nuclear@3: } nuclear@3: } nuclear@3: nuclear@3: // Scans till the end of protocol. Returns first character past protocol, nuclear@3: // 0 if not found. nuclear@3: // - protocol: 'file://', 'http://' nuclear@3: const char* ScanPathProtocol(const char* url) nuclear@3: { nuclear@3: UInt32 charVal = UTF8Util::DecodeNextChar(&url); nuclear@3: UInt32 charVal2; nuclear@3: nuclear@3: while (charVal != 0) nuclear@3: { nuclear@3: // Treat a colon followed by a slash as absolute. nuclear@3: if (charVal == ':') nuclear@3: { nuclear@3: charVal2 = UTF8Util::DecodeNextChar(&url); nuclear@3: charVal = UTF8Util::DecodeNextChar(&url); nuclear@3: if ((charVal == '/') && (charVal2 == '\\')) nuclear@3: return url; nuclear@3: } nuclear@3: charVal = UTF8Util::DecodeNextChar(&url); nuclear@3: } nuclear@3: return 0; nuclear@3: } nuclear@3: nuclear@3: nuclear@3: //-------------------------------------------------------------------- nuclear@3: // ***** String Path API implementation nuclear@3: nuclear@3: bool String::HasAbsolutePath(const char* url) nuclear@3: { nuclear@3: // Absolute paths can star with: nuclear@3: // - protocols: 'file://', 'http://' nuclear@3: // - windows drive: 'c:\' nuclear@3: // - UNC share name: '\\share' nuclear@3: // - unix root '/' nuclear@3: nuclear@3: // On the other hand, relative paths are: nuclear@3: // - directory: 'directory/file' nuclear@3: // - this directory: './file' nuclear@3: // - parent directory: '../file' nuclear@3: // nuclear@3: // For now, we don't parse '.' or '..' out, but instead let it be concatenated nuclear@3: // to string and let the OS figure it out. This, however, is not good for file nuclear@3: // name matching in library/etc, so it should be improved. nuclear@3: nuclear@3: if (!url || !*url) nuclear@3: return true; // Treat empty strings as absolute. nuclear@3: nuclear@3: UInt32 charVal = UTF8Util::DecodeNextChar(&url); nuclear@3: nuclear@3: // Fist character of '/' or '\\' means absolute url. nuclear@3: if ((charVal == '/') || (charVal == '\\')) nuclear@3: return true; nuclear@3: nuclear@3: while (charVal != 0) nuclear@3: { nuclear@3: // Treat a colon followed by a slash as absolute. nuclear@3: if (charVal == ':') nuclear@3: { nuclear@3: charVal = UTF8Util::DecodeNextChar(&url); nuclear@3: // Protocol or windows drive. Absolute. nuclear@3: if ((charVal == '/') || (charVal == '\\')) nuclear@3: return true; nuclear@3: } nuclear@3: else if ((charVal == '/') || (charVal == '\\')) nuclear@3: { nuclear@3: // Not a first character (else 'if' above the loop would have caught it). nuclear@3: // Must be a relative url. nuclear@3: break; nuclear@3: } nuclear@3: nuclear@3: charVal = UTF8Util::DecodeNextChar(&url); nuclear@3: } nuclear@3: nuclear@3: // We get here for relative paths. nuclear@3: return false; nuclear@3: } nuclear@3: nuclear@3: nuclear@3: bool String::HasExtension(const char* path) nuclear@3: { nuclear@3: const char* ext = 0; nuclear@3: ScanFilePath(path, 0, &ext); nuclear@3: return ext != 0; nuclear@3: } nuclear@3: bool String::HasProtocol(const char* path) nuclear@3: { nuclear@3: return ScanPathProtocol(path) != 0; nuclear@3: } nuclear@3: nuclear@3: nuclear@3: String String::GetPath() const nuclear@3: { nuclear@3: const char* filename = 0; nuclear@3: ScanFilePath(ToCStr(), &filename, 0); nuclear@3: nuclear@3: // Technically we can have extra logic somewhere for paths, nuclear@3: // such as enforcing protocol and '/' only based on flags, nuclear@3: // but we keep it simple for now. nuclear@3: return String(ToCStr(), filename ? (filename-ToCStr()) : GetSize()); nuclear@3: } nuclear@3: nuclear@3: String String::GetProtocol() const nuclear@3: { nuclear@3: const char* protocolEnd = ScanPathProtocol(ToCStr()); nuclear@3: return String(ToCStr(), protocolEnd ? (protocolEnd-ToCStr()) : 0); nuclear@3: } nuclear@3: nuclear@3: String String::GetFilename() const nuclear@3: { nuclear@3: const char* filename = 0; nuclear@3: ScanFilePath(ToCStr(), &filename, 0); nuclear@3: return String(filename); nuclear@3: } nuclear@3: String String::GetExtension() const nuclear@3: { nuclear@3: const char* ext = 0; nuclear@3: ScanFilePath(ToCStr(), 0, &ext); nuclear@3: return String(ext); nuclear@3: } nuclear@3: nuclear@3: void String::StripExtension() nuclear@3: { nuclear@3: const char* ext = 0; nuclear@3: ScanFilePath(ToCStr(), 0, &ext); nuclear@3: if (ext) nuclear@3: { nuclear@3: *this = String(ToCStr(), ext-ToCStr()); nuclear@3: } nuclear@3: } nuclear@3: nuclear@3: void String::StripProtocol() nuclear@3: { nuclear@3: const char* protocol = ScanPathProtocol(ToCStr()); nuclear@3: if (protocol) nuclear@3: AssignString(protocol, OVR_strlen(protocol)); nuclear@3: } nuclear@3: nuclear@3: } // OVR