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