nuclear@0: /************************************************************************************ nuclear@0: nuclear@0: Filename : OVR_String_PathUtil.cpp nuclear@0: Content : String filename/url helper function nuclear@0: Created : September 19, 2012 nuclear@0: Notes : nuclear@0: nuclear@0: Copyright : Copyright 2014 Oculus VR, LLC All Rights reserved. nuclear@0: nuclear@0: Licensed under the Oculus VR Rift SDK License Version 3.2 (the "License"); nuclear@0: you may not use the Oculus VR Rift SDK except in compliance with the License, nuclear@0: which is provided at the time of installation or download, or which nuclear@0: otherwise accompanies this software in either electronic or hard copy form. nuclear@0: nuclear@0: You may obtain a copy of the License at nuclear@0: nuclear@0: http://www.oculusvr.com/licenses/LICENSE-3.2 nuclear@0: nuclear@0: Unless required by applicable law or agreed to in writing, the Oculus VR SDK nuclear@0: distributed under the License is distributed on an "AS IS" BASIS, nuclear@0: WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. nuclear@0: See the License for the specific language governing permissions and nuclear@0: limitations under the License. nuclear@0: nuclear@0: ************************************************************************************/ nuclear@0: nuclear@0: #include "OVR_String.h" nuclear@0: #include "OVR_UTF8Util.h" nuclear@0: nuclear@0: namespace OVR { nuclear@0: nuclear@0: //-------------------------------------------------------------------- nuclear@0: // ***** Path-Scanner helper function nuclear@0: nuclear@0: // Scans file path finding filename start and extension start, fills in their addess. nuclear@0: void ScanFilePath(const char* url, const char** pfilename, const char** pext) nuclear@0: { nuclear@0: const char* urlStart = url; nuclear@0: const char *filename = 0; nuclear@0: const char *lastDot = 0; nuclear@0: nuclear@0: uint32_t charVal = UTF8Util::DecodeNextChar(&url); nuclear@0: nuclear@0: while (charVal != 0) nuclear@0: { nuclear@0: if ((charVal == '/') || (charVal == '\\')) nuclear@0: { nuclear@0: filename = url; nuclear@0: lastDot = 0; nuclear@0: } nuclear@0: else if (charVal == '.') nuclear@0: { nuclear@0: lastDot = url - 1; nuclear@0: } nuclear@0: nuclear@0: charVal = UTF8Util::DecodeNextChar(&url); nuclear@0: } nuclear@0: nuclear@0: if (pfilename) nuclear@0: { nuclear@0: // It was a naked filename nuclear@0: if (urlStart && (*urlStart != '.') && *urlStart) nuclear@0: *pfilename = urlStart; nuclear@0: else nuclear@0: *pfilename = filename; nuclear@0: } nuclear@0: nuclear@0: if (pext) nuclear@0: { nuclear@0: *pext = lastDot; nuclear@0: } nuclear@0: } nuclear@0: nuclear@0: // Scans till the end of protocol. Returns first character past protocol, nuclear@0: // 0 if not found. nuclear@0: // - protocol: 'file://', 'http://' nuclear@0: const char* ScanPathProtocol(const char* url) nuclear@0: { nuclear@0: uint32_t charVal = UTF8Util::DecodeNextChar(&url); nuclear@0: uint32_t charVal2; nuclear@0: nuclear@0: while (charVal != 0) nuclear@0: { nuclear@0: // Treat a colon followed by a slash as absolute. nuclear@0: if (charVal == ':') nuclear@0: { nuclear@0: charVal2 = UTF8Util::DecodeNextChar(&url); nuclear@0: charVal = UTF8Util::DecodeNextChar(&url); nuclear@0: if ((charVal == '/') && (charVal2 == '\\')) nuclear@0: return url; nuclear@0: } nuclear@0: charVal = UTF8Util::DecodeNextChar(&url); nuclear@0: } nuclear@0: return 0; nuclear@0: } nuclear@0: nuclear@0: nuclear@0: //-------------------------------------------------------------------- nuclear@0: // ***** String Path API implementation nuclear@0: nuclear@0: bool String::HasAbsolutePath(const char* url) nuclear@0: { nuclear@0: // Absolute paths can star with: nuclear@0: // - protocols: 'file://', 'http://' nuclear@0: // - windows drive: 'c:\' nuclear@0: // - UNC share name: '\\share' nuclear@0: // - unix root '/' nuclear@0: nuclear@0: // On the other hand, relative paths are: nuclear@0: // - directory: 'directory/file' nuclear@0: // - this directory: './file' nuclear@0: // - parent directory: '../file' nuclear@0: // nuclear@0: // For now, we don't parse '.' or '..' out, but instead let it be concatenated nuclear@0: // to string and let the OS figure it out. This, however, is not good for file nuclear@0: // name matching in library/etc, so it should be improved. nuclear@0: nuclear@0: if (!url || !*url) nuclear@0: return true; // Treat empty strings as absolute. nuclear@0: nuclear@0: uint32_t charVal = UTF8Util::DecodeNextChar(&url); nuclear@0: nuclear@0: // Fist character of '/' or '\\' means absolute url. nuclear@0: if ((charVal == '/') || (charVal == '\\')) nuclear@0: return true; nuclear@0: nuclear@0: while (charVal != 0) nuclear@0: { nuclear@0: // Treat a colon followed by a slash as absolute. nuclear@0: if (charVal == ':') nuclear@0: { nuclear@0: charVal = UTF8Util::DecodeNextChar(&url); nuclear@0: // Protocol or windows drive. Absolute. nuclear@0: if ((charVal == '/') || (charVal == '\\')) nuclear@0: return true; nuclear@0: } nuclear@0: else if ((charVal == '/') || (charVal == '\\')) nuclear@0: { nuclear@0: // Not a first character (else 'if' above the loop would have caught it). nuclear@0: // Must be a relative url. nuclear@0: break; nuclear@0: } nuclear@0: nuclear@0: charVal = UTF8Util::DecodeNextChar(&url); nuclear@0: } nuclear@0: nuclear@0: // We get here for relative paths. nuclear@0: return false; nuclear@0: } nuclear@0: nuclear@0: nuclear@0: bool String::HasExtension(const char* path) nuclear@0: { nuclear@0: const char* ext = 0; nuclear@0: ScanFilePath(path, 0, &ext); nuclear@0: return ext != 0; nuclear@0: } nuclear@0: bool String::HasProtocol(const char* path) nuclear@0: { nuclear@0: return ScanPathProtocol(path) != 0; nuclear@0: } nuclear@0: nuclear@0: nuclear@0: String String::GetPath() const nuclear@0: { nuclear@0: const char* filename = 0; nuclear@0: ScanFilePath(ToCStr(), &filename, 0); nuclear@0: nuclear@0: // Technically we can have extra logic somewhere for paths, nuclear@0: // such as enforcing protocol and '/' only based on flags, nuclear@0: // but we keep it simple for now. nuclear@0: return String(ToCStr(), filename ? (filename-ToCStr()) : GetSize()); nuclear@0: } nuclear@0: nuclear@0: String String::GetProtocol() const nuclear@0: { nuclear@0: const char* protocolEnd = ScanPathProtocol(ToCStr()); nuclear@0: return String(ToCStr(), protocolEnd ? (protocolEnd-ToCStr()) : 0); nuclear@0: } nuclear@0: nuclear@0: String String::GetFilename() const nuclear@0: { nuclear@0: const char* filename = 0; nuclear@0: ScanFilePath(ToCStr(), &filename, 0); nuclear@0: return String(filename); nuclear@0: } nuclear@0: String String::GetExtension() const nuclear@0: { nuclear@0: const char* ext = 0; nuclear@0: ScanFilePath(ToCStr(), 0, &ext); nuclear@0: return String(ext); nuclear@0: } nuclear@0: nuclear@0: void String::StripExtension() nuclear@0: { nuclear@0: const char* ext = 0; nuclear@0: ScanFilePath(ToCStr(), 0, &ext); nuclear@0: if (ext) nuclear@0: { nuclear@0: *this = String(ToCStr(), ext-ToCStr()); nuclear@0: } nuclear@0: } nuclear@0: nuclear@0: void String::StripProtocol() nuclear@0: { nuclear@0: const char* protocol = ScanPathProtocol(ToCStr()); nuclear@0: if (protocol) nuclear@0: AssignString(protocol, OVR_strlen(protocol)); nuclear@0: } nuclear@0: nuclear@0: } // OVR