const char *DefaultLangRegion() { // Unfortunate default. There's no need to use bFirstRun, since this is only a default. static std::string defaultLangRegion = "en_US"; std::string langRegion = System_GetProperty(SYSPROP_LANGREGION); if (i18nrepo.IniExists(langRegion)) { defaultLangRegion = langRegion; } else if (langRegion.length() >= 3) { // Don't give up. Let's try a fuzzy match - so nl_BE can match nl_NL. IniFile mapping; mapping.LoadFromVFS("langregion.ini"); std::vector<std::string> keys; mapping.GetKeys("LangRegionNames", keys); for (std::string key : keys) { if (startsWithNoCase(key, langRegion)) { // Exact submatch, or different case. Let's use it. defaultLangRegion = key; break; } else if (startsWithNoCase(key, langRegion.substr(0, 3))) { // Best so far. defaultLangRegion = key; } } } return defaultLangRegion.c_str(); }
void HTTPFileLoader::Prepare() { std::call_once(preparedFlag_, [this](){ if (!client_.Resolve(url_.Host().c_str(), url_.Port())) { // TODO: Should probably set some flag? return; } Connect(); int err = client_.SendRequest("HEAD", url_.Resource().c_str()); if (err < 0) { Disconnect(); return; } Buffer readbuf; std::vector<std::string> responseHeaders; int code = client_.ReadResponseHeaders(&readbuf, responseHeaders); if (code != 200) { // Leave size at 0, invalid. ERROR_LOG(LOADER, "HTTP request failed, got %03d for %s", code, filename_.c_str()); Disconnect(); return; } // TODO: Expire cache via ETag, etc. bool acceptsRange = false; for (std::string header : responseHeaders) { if (startsWithNoCase(header, "Content-Length:")) { size_t size_pos = header.find_first_of(' '); if (size_pos != header.npos) { size_pos = header.find_first_not_of(' ', size_pos); } if (size_pos != header.npos) { filesize_ = atoll(&header[size_pos]); } } if (startsWithNoCase(header, "Accept-Ranges:")) { std::string lowerHeader = header; std::transform(lowerHeader.begin(), lowerHeader.end(), lowerHeader.begin(), tolower); // TODO: Delimited. if (lowerHeader.find("bytes") != lowerHeader.npos) { acceptsRange = true; } } } // TODO: Keepalive instead. Disconnect(); if (!acceptsRange) { WARN_LOG(LOADER, "HTTP server did not advertise support for range requests."); } if (filesize_ == 0) { ERROR_LOG(LOADER, "Could not determine file size for %s", filename_.c_str()); } // If we didn't end up with a filesize_ (e.g. chunked response), give up. File invalid. }); }
static void checkTerm(char *term, char *target, enum dbDbMatchType type, struct dbDb *dbDb, struct hash *matchHash, struct dbDbMatch **pMatchList) /* If target starts with term (case-insensitive), and target is not already in matchHash, * add target to matchHash and add a new match to pMatchList. */ { // Make uppercase version of target for case-insensitive matching. int targetLen = strlen(target); char targetUpcase[targetLen + 1]; safencpy(targetUpcase, sizeof(targetUpcase), target, targetLen); touppers(targetUpcase); int offset = wordMatchOffset(term, targetUpcase); if (offset >= 0) { addIfFirstMatch(dbDb, type, offset, targetUpcase, term, matchHash, pMatchList); } else if (offset < 0 && type == ddmtSciName && term[0] == targetUpcase[0]) { // For scientific names ("Genus species"), see if the user entered the term as 'G. species' // e.g. term 'P. trog' for target 'Pan troglodytes' regmatch_t substrArr[3]; if (regexMatchSubstrNoCase(term, "^[a-z](\\.| ) *([a-z]+)", substrArr, ArraySize(substrArr))) { char *termSpecies = term + substrArr[2].rm_so; char *targetSpecies = skipLeadingSpaces(skipToSpaces(targetUpcase)); if (targetSpecies && startsWithNoCase(termSpecies, targetSpecies)) { // Keep the negative offset since we can't just bold one chunk of target... addIfFirstMatch(dbDb, type, offset, targetUpcase, term, matchHash, pMatchList); } } } }
TokenFilter* TokenFilter::detachFilter(const tstring& szIdentifier) { TokenFilter* pPreFilter = m_pPreFilter; if(pPreFilter) { if(startsWithNoCase(pPreFilter->getIdentifier(), szIdentifier)) { m_pPreFilter = NULL; return pPreFilter; } } return NULL; }
extern "C" jstring Java_org_ppsspp_ppsspp_ShortcutActivity_queryGameName(JNIEnv *env, jclass, jstring jpath) { std::string path = GetJavaString(env, jpath); std::string result = ""; GameInfoCache *cache = new GameInfoCache(); std::shared_ptr<GameInfo> info = cache->GetInfo(nullptr, path, 0); // Wait until it's done: this is synchronous, unfortunately. if (info) { cache->WaitUntilDone(info); if (info->fileType != IdentifiedFileType::UNKNOWN) { result = info->GetTitle(); // Pretty arbitrary, but the home screen will often truncate titles. // Let's remove "The " from names since it's common in English titles. if (result.length() > strlen("The ") && startsWithNoCase(result, "The ")) { result = result.substr(strlen("The ")); } } } delete cache; return env->NewStringUTF(result.c_str()); }
size_t HTTPFileLoader::ReadAt(s64 absolutePos, size_t bytes, void *data) { s64 absoluteEnd = std::min(absolutePos + (s64)bytes, filesize_); if (absolutePos >= filesize_ || bytes == 0) { // Read outside of the file or no read at all, just fail immediately. return 0; } Connect(); char requestHeaders[4096]; // Note that the Range header is *inclusive*. snprintf(requestHeaders, sizeof(requestHeaders), "Range: bytes=%lld-%lld\r\n", absolutePos, absoluteEnd - 1); int err = client_.SendRequest("GET", url_.Resource().c_str(), requestHeaders, nullptr); if (err < 0) { Disconnect(); return 0; } Buffer readbuf; std::vector<std::string> responseHeaders; int code = client_.ReadResponseHeaders(&readbuf, responseHeaders); if (code != 206) { ERROR_LOG(LOADER, "HTTP server did not respond with range, received code=%03d", code); Disconnect(); return 0; } // TODO: Expire cache via ETag, etc. // We don't support multipart/byteranges responses. bool supportedResponse = false; for (std::string header : responseHeaders) { if (startsWithNoCase(header, "Content-Range:")) { // TODO: More correctness. Whitespace can be missing or different. s64 first = -1, last = -1, total = -1; std::string lowerHeader = header; std::transform(lowerHeader.begin(), lowerHeader.end(), lowerHeader.begin(), tolower); if (sscanf(lowerHeader.c_str(), "content-range: bytes %lld-%lld/%lld", &first, &last, &total) >= 2) { if (first == absolutePos && last == absoluteEnd - 1) { supportedResponse = true; } else { ERROR_LOG(LOADER, "Unexpected HTTP range: got %lld-%lld, wanted %lld-%lld.", first, last, absolutePos, absoluteEnd - 1); } } else { ERROR_LOG(LOADER, "Unexpected HTTP range response: %s", header.c_str()); } } } // TODO: Would be nice to read directly. Buffer output; int res = client_.ReadResponseEntity(&readbuf, responseHeaders, &output); if (res != 0) { ERROR_LOG(LOADER, "Unable to read HTTP response entity: %d", res); // Let's take anything we got anyway. Not worse than returning nothing? } // TODO: Keepalive instead. Disconnect(); if (!supportedResponse) { ERROR_LOG(LOADER, "HTTP server did not respond with the range we wanted."); return 0; } size_t readBytes = output.size(); output.Take(readBytes, (char *)data); filepos_ = absolutePos + readBytes; return readBytes; }
HTTPFileLoader::HTTPFileLoader(const std::string &filename) : filesize_(0), filepos_(0), url_(filename), filename_(filename), connected_(false) { if (!client_.Resolve(url_.Host().c_str(), url_.Port())) { return; } Connect(); int err = client_.SendRequest("HEAD", url_.Resource().c_str()); if (err < 0) { Disconnect(); return; } Buffer readbuf; std::vector<std::string> responseHeaders; int code = client_.ReadResponseHeaders(&readbuf, responseHeaders); if (code != 200) { // Leave size at 0, invalid. ERROR_LOG(LOADER, "HTTP request failed, got %03d for %s", code, filename.c_str()); Disconnect(); return; } // TODO: Expire cache via ETag, etc. bool acceptsRange = false; for (std::string header : responseHeaders) { if (startsWithNoCase(header, "Content-Length:")) { size_t size_pos = header.find_first_of(' '); if (size_pos != header.npos) { size_pos = header.find_first_not_of(' ', size_pos); } if (size_pos != header.npos) { // TODO: Find a way to get this to work right on Symbian? #ifndef __SYMBIAN32__ filesize_ = atoll(&header[size_pos]); #else filesize_ = atoi(&header[size_pos]); #endif } } if (startsWithNoCase(header, "Accept-Ranges:")) { std::string lowerHeader = header; std::transform(lowerHeader.begin(), lowerHeader.end(), lowerHeader.begin(), tolower); // TODO: Delimited. if (lowerHeader.find("bytes") != lowerHeader.npos) { acceptsRange = true; } } } // TODO: Keepalive instead. Disconnect(); if (!acceptsRange) { WARN_LOG(LOADER, "HTTP server did not advertise support for range requests."); } if (filesize_ == 0) { ERROR_LOG(LOADER, "Could not determine file size for %s", filename.c_str()); } // If we didn't end up with a filesize_ (e.g. chunked response), give up. File invalid. }