File::File(const AnyString& filePath): pFormat(nullptr) { if (filePath.empty()) return; # if LIBAVFORMAT_VERSION_MAJOR < 53 if (::av_open_input_file(&pFormat, filePath.c_str(), nullptr, 0, nullptr)) # else if (::avformat_open_input(&pFormat, filePath.c_str(), nullptr, nullptr)) # endif // LIBAVFORMAT_VERSION_MAJOR < 53 { pFormat = nullptr; return; } // After opening, we must search for the stream information because not // all formats will have it in stream headers (eg. system MPEG streams) # if LIBAVFORMAT_VERSION_MAJOR < 53 if (::av_find_stream_info(pFormat) < 0) # else if (::avformat_find_stream_info(pFormat, nullptr) < 0) # endif // LIBAVFORMAT_VERSION_MAJOR < 53 { # if LIBAVFORMAT_VERSION_MAJOR < 53 ::av_close_input_file(pFormat); # else ::avformat_close_input(&pFormat); # endif // LIBAVFORMAT_VERSION_MAJOR < 53 pFormat = nullptr; return; } }
DBI::Error Transaction::truncate(const AnyString& tablename) { if (YUNI_UNLIKELY(not IsValidIdentifier(tablename))) return errInvalidIdentifier; assert(!(!pChannel)); // the adapter ::yn_dbi_adapter& adapter = pChannel->adapter; // The DBI interface should provide the most appropriate way for // truncating a table (autoincrement / cascade...) if (YUNI_LIKELY(adapter.truncate)) { return (DBI::Error) adapter.truncate(adapter.dbh, tablename.c_str(), tablename.size()); } else { // Fallback to a failsafe method // -- stmt << "TRUNCATE " << tablename << ';'; // The SQL command Truncate is not supported by all databases. `DELETE FROM` // is not the most efficient way for truncating a table // but it should work almost everywhere String stmt; stmt << "DELETE FROM " << tablename << ';'; return perform(stmt); } }
Cursor Transaction::prepare(const AnyString& stmt) { assert(!(!pChannel)); // the adapter ::yn_dbi_adapter& adapter = pChannel->adapter; if (YUNI_UNLIKELY(nullHandle == pTxHandle)) { if (errNone != pChannel->begin(pTxHandle)) return Cursor(adapter, nullptr); } // query handle void* handle = nullptr; if (YUNI_LIKELY(not stmt.empty() and adapter.dbh)) { assert(adapter.query_new != NULL and "invalid adapter query_new"); assert(adapter.query_ref_acquire != NULL and "invalid adapter query_ref_acquire"); assert(adapter.query_ref_release != NULL and "invalid adapter query_ref_release"); adapter.query_new(&handle, adapter.dbh, stmt.c_str(), stmt.size()); } return Cursor(adapter, handle); }
int Luhn::Mod10(const AnyString& s) { // The string must have at least one char if (s.size() > 1) { // The algorithm : // 1 - Counting from the check digit, which is the rightmost, and moving // left, double the value of every second digit. // 2 - Sum the digits of the products together with the undoubled digits // from the original number. // 3 - If the total ends in 0 (put another way, if the total modulo 10 is // congruent to 0), then the number is valid according to the Luhn formula // static const int prefetch[] = {0, 2, 4, 6, 8, 1, 3, 5, 7, 9}; int sum = 0; bool alternate = true; const AnyString::iterator end = s.end(); // For each char for (AnyString::iterator i = s.begin(); end != i; ++i) { // Each char in the string must be a digit if (!String::IsDigit(i.value())) return false; // The `real` digit int n = i.value() - '0'; // Computing the sum sum += (alternate = !alternate) ? prefetch[n] : n; } return sum % 10; } return -1; }
bool Size(const AnyString& filename, uint64& value) { struct stat results; if (not filename.empty() && stat(filename.c_str(), &results) == 0) { value = (uint64) results.st_size; return true; } value = 0u; return false; }
Yuni::IO::NodeType TypeOf(const AnyString& filename) { if (filename.empty()) return Yuni::IO::typeUnknown; # ifdef YUNI_OS_WINDOWS const char* p = filename.c_str(); unsigned int len = filename.size(); if (p[len - 1] == '\\' or p[len - 1] == '/') { if (!--len) { # ifdef YUNI_OS_WINDOWS return Yuni::IO::typeUnknown; # else // On Unixes, `/` is a valid folder return Yuni::IO::typeFolder; # endif } } // Driver letters if (len == 2 and p[1] == ':') return Yuni::IO::typeFolder; String norm; Yuni::IO::Normalize(norm, AnyString(p, len)); // Conversion into wchar_t Private::WString<true> wstr(norm); if (wstr.empty()) return Yuni::IO::typeUnknown; WIN32_FILE_ATTRIBUTE_DATA infoFile; if (!GetFileAttributesExW(wstr.c_str(), GetFileExInfoStandard, &infoFile)) return Yuni::IO::typeUnknown; return ((infoFile.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) != 0) ? Yuni::IO::typeFolder : Yuni::IO::typeFile; # else // WINDOWS struct stat s; if (stat(filename.c_str(), &s) != 0) return Yuni::IO::typeUnknown; return (S_ISDIR(s.st_mode)) ? Yuni::IO::typeFolder : Yuni::IO::typeFile; # endif }
bool Size(const AnyString& filename, uint64& value) { unsigned int len = filename.size(); if (!len) { value = 0u; return false; } const char* const p = filename.c_str(); if (p[len - 1] == '\\' || p[len - 1] == '/') --len; // Driver letters if (len == 2 && p[1] == ':') { value = 0u; return true; } String norm; Yuni::IO::Normalize(norm, p, len); // Conversion into wchar_t Private::WString<true> wstr(norm); if (wstr.empty()) { value = 0u; return false; } HANDLE hndl = CreateFileW(wstr.c_str(), 0, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); if (hndl == INVALID_HANDLE_VALUE) { value = 0u; return false; } LARGE_INTEGER v; if (!GetFileSizeEx(hndl, &v)) { CloseHandle(hndl); value = 0u; return false; } value = (uint64) v.QuadPart; CloseHandle(hndl); return true; }
PathFormat::PathFormat(LoggingFacility& logs, const AnyString& format) : logs(logs), pFolderPart(nullptr), pFilePart(nullptr) { if (format.contains('(')) throw GenericTools::Exception("Format shouldn't include any parenthesis"); { String folderName, fileName; // Split the path and the filename IO::ExtractFilePath(folderName, format, false); if (folderName.empty()) fileName = format; else { IO::ExtractFileName(fileName, format, false); if (IO::Separator != '/') { if (IO::Separator == '\\') folderName.replace("/", "\\\\"); else folderName.replace('/', IO::Separator); } logs.notice("Folder = ") << folderName; pFolderPart = new Private::PathFormatHelper(logs, folderName); } logs.notice("File = ") << fileName; pFilePart = new Private::PathFormatHelper(logs, fileName); } }
NodeType TypeOf(const AnyString& filename, bool followSymLink) { yuint64 size; // useless yint64 lastModified; return (YUNI_LIKELY(not filename.empty())) ? Stat(filename, size, lastModified, followSymLink) : IO::typeUnknown; }
NodeType FetchFileStatus(const AnyString& filename, yuint64& size, yint64& lastModified, bool followSymLink) { size = 0u; lastModified = 0; return (YUNI_LIKELY(not filename.empty())) ? Stat(filename, size, lastModified, followSymLink) : IO::typeUnknown; }
bool VertexShader::loadFromMemory(const AnyString& source) { if (pID == invalidID) pID = ::glCreateShader(GL_VERTEX_SHADER); const char* data = source.data(); ::glShaderSource(pID, 1, &data, nullptr); ::glCompileShader(pID); return GLTestError("VertexShader::loadFromMemory"); }
Yuni::IO::Error Delete(const AnyString& filename) { // DeleteFile is actually a macro and will be replaced by DeleteFileW // with Visual Studio. Consequently we can not use the word DeleteFile..... if (filename.empty()) return Yuni::IO::errUnknown; # ifndef YUNI_OS_WINDOWS return (unlink(filename.c_str())) ? Yuni::IO::errUnknown : Yuni::IO::errNone; # else const char* const p = filename.c_str(); uint len = filename.size(); if (p[len - 1] == '\\' or p[len - 1] == '/') --len; // Driver letters if (len == 2 and p[1] == ':') return Yuni::IO::errBadFilename; String norm; Yuni::IO::Normalize(norm, AnyString(p, len)); // Conversion into wchar_t WString wstr(norm, true); if (wstr.empty()) return Yuni::IO::errUnknown; wstr.replace('/', '\\'); return (DeleteFileW(wstr.c_str())) ? Yuni::IO::errNone : Yuni::IO::errUnknown; # endif }
bool Create(const AnyString& path, uint mode) { if (not path.empty() and not Yuni::IO::Exists(path)) { # ifdef YUNI_OS_WINDOWS // `mode` is not used on Windows (void) mode; return WindowsMake(path); # else return UnixMake(path, mode); # endif } return true; }
DBI::Error Transaction::perform(const AnyString& script) { assert(!(!pChannel)); // the adapter ::yn_dbi_adapter& adapter = pChannel->adapter; assert(adapter.query_exec != NULL); if (YUNI_LIKELY(nullHandle != pTxHandle)) { return (DBI::Error) adapter.query_exec(adapter.dbh, script.c_str(), script.size()); } else { // start a new transaction DBI::Error error = pChannel->begin(pTxHandle); if (YUNI_LIKELY(error == errNone)) error = (DBI::Error) adapter.query_exec(adapter.dbh, script.c_str(), script.size()); return error; } }
static bool UnixMake(const AnyString& path, uint mode) { const uint len = path.size(); char* buffer = new char[len + 1]; YUNI_MEMCPY(buffer, len, path.c_str(), len); buffer[len] = '\0'; char* pt = buffer; char tmp; do { if ('\\' == *pt or '/' == *pt or '\0' == *pt) { tmp = *pt; *pt = '\0'; if ('\0' != buffer[0] and '\0' != buffer[1] and '\0' != buffer[2]) { if (mkdir(buffer, static_cast<mode_t>(mode)) < 0) { if (errno != EEXIST and errno != EISDIR and errno != ENOSYS) { delete[] buffer; return false; } } } if ('\0' == tmp) break; *pt = tmp; } ++pt; } while (true); delete[] buffer; return true; }
sint64 LastModificationTime(const AnyString& filename) { # ifdef YUNI_OS_WINDOWS Private::WString<> wfilenm(filename); if (wfilenm.empty()) return 0; HANDLE hFile = CreateFileW(wfilenm.c_str(), GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL); if (hFile == INVALID_HANDLE_VALUE) return 0; FILETIME ftCreate, ftAccess, ftWrite; // Retrieve the file times for the file. if (GetFileTime(hFile, &ftCreate, &ftAccess, &ftWrite)) { CloseHandle(hFile); LARGE_INTEGER date, adjust; date.HighPart = ftWrite.dwHighDateTime; date.LowPart = ftWrite.dwLowDateTime; // 100-nanoseconds = milliseconds * 10000 adjust.QuadPart = 11644473600000 * 10000; // removes the diff between 1970 and 1601 date.QuadPart -= adjust.QuadPart; // converts back from 100-nanoseconds to seconds return date.QuadPart / 10000000; } CloseHandle(hFile); return 0; # else // UNIX struct stat st; if (!stat(filename.c_str(), &st)) return st.st_mtime; return 0; # endif }
bool Stream::open(const AnyString& filename, int mode) { // Close the file if already opened if (pFd) (void)::fclose(pFd); # ifdef YUNI_OS_WINDOWS pFd = OpenFileOnWindows(filename, mode); # else // It is mandatory to open file with the flag O_CLOEXEC to avoid race // conditions with fork // fopen should used O_CLOEXEC as one of the option. However, at the current // state, not all operating systems do that. // So we have to do it by ourselves with open and fdopen. /*int flag = O_CLOEXEC; if (0 != (mode & OpenMode::read) and 0 != (mode & OpenMode::write)) flag |= O_RDWR; else if (0 != (mode & OpenMode::read)) flag |= O_RDONLY; else if (0 != (mode & OpenMode::write)) flag |= O_WRONLY; if (0 != (mode & OpenMode::truncate)) flag |= O_TRUNC; else if (0 != (mode & OpenMode::append)) flag |= O_APPEND; if (0 != (mode & ~OpenMode::read)) flag |= O_CREAT; int fd = ::open(filename.c_str(), flag); if (fd < 0) // error pFd = nullptr; else pFd = ::fdopen(fd, OpenMode::ToCString(mode));*/ pFd = ::fopen(filename.c_str(), OpenMode::ToCString(mode)); # endif return (NULL != pFd); }
void WString::prepareWString(const AnyString& string, bool uncprefix) { if (string.empty()) { if (uncprefix) { pSize = 4; pWString = (wchar_t*)::realloc(pWString, sizeof(wchar_t) * 5); pWString[0] = L'\\'; pWString[1] = L'\\'; pWString[2] = L'?'; pWString[3] = L'\\'; pWString[4] = L'\0'; } else clear(); return; } if (string.size() > INT_MAX) { clear(); return; } // Offset according to the presence of the UNC prefix const uint offset = (not uncprefix) ? 0 : 4; #ifdef YUNI_OS_WINDOWS { // Allocate and convert the C-String. Several iterations may be required // for allocating enough room for the conversion. const int sizeRequired = MultiByteToWideChar(CP_UTF8, 0, string.c_str(), string.size(), nullptr, 0); if (sizeRequired <= 0) { clear(); return; } pSize = sizeRequired + offset; pWString = (wchar_t*) realloc(pWString, sizeof(wchar_t) * (pSize + 1)); if (nullptr == pWString) // Impossible to allocate the buffer. Aborting. { clear(); return; } // Converting into Wide String const int n = MultiByteToWideChar(CP_UTF8, 0, string.c_str(), static_cast<int>(string.size()), pWString + offset, static_cast<int>(pSize - offset)); if (n != sizeRequired) { assert(false and "most likely an error"); clear(); return; } } #else { const char* wcstr = string.c_str(); mbstate_t state; memset (&state, '\0', sizeof (state)); size_t sizeRequired = mbsnrtowcs(nullptr, &wcstr, string.size(), 0, &state); if (0 == sizeRequired or (size_t) -1 == sizeRequired) { clear(); return; } pSize = sizeRequired + offset; pWString = (wchar_t*) realloc(pWString, sizeof(wchar_t) * (pSize + 1)); if (nullptr == pWString) // Impossible to allocate the buffer. Aborting. { clear(); return; } memset (&state, '\0', sizeof (state)); size_t written = mbsnrtowcs(pWString + offset, &wcstr, string.size(), pSize - offset, &state); if (0 == written or (size_t) -1 == written) { clear(); return; } } #endif // prepend the Windows UNC prefix if (uncprefix) { pWString[0] = L'\\'; pWString[1] = L'\\'; pWString[2] = L'?'; pWString[3] = L'\\'; } // always ensure that the string is zero terminated pWString[pSize] = L'\0'; }
void Program::commandLine(AnyString cmd) { // remove all whitespaces cmd.trim(); auto envptr = pEnv; // keeping a reference to the current env if (!envptr) { envptr = std::make_shared<ProcessSharedInfo>(); pEnv = envptr; } ProcessSharedInfo& env = *envptr; MutexLocker locker(env.mutex); env.executable.clear(); env.arguments.clear(); if (cmd.empty()) return; String* str = &env.executable; char instring = '\0'; const AnyString::null_iterator end = cmd.utf8end(); for (AnyString::const_utf8iterator i = cmd.utf8begin(); i != end; ++i) { char c = *i; switch (c) { default: { *str += i.value(); break; } case '"': [[fallthrough]]; case '\'': { if (instring == '\0') { instring = c; } else { if (instring == c) instring = '\0'; else *str += c; } break; } case '\\': { ++i; if (YUNI_UNLIKELY(i == end)) return; c = *i; switch (c) { case 'n': (*str) += '\n'; break; case 't': (*str) += '\t'; break; case 'r': (*str) += '\r'; break; case 'b': (*str) += '\b'; break; case 'f': (*str) += '\f'; break; case 'v': (*str) += '\v'; break; case '0': (*str) += '\0'; break; case 'e': [[fallthrough]]; case 'a': [[fallthrough]]; case 'E': break; default: (*str) << '\\' << c; break; } break; } case ' ': [[fallthrough]]; case '\t': { if (instring == '\0') { if (not str->empty()) { env.arguments.push_back(nullptr); str = &(env.arguments.back()); } } else *str += c; break; } } } }
static bool DecodeURLQuery(KeyValueStore& params, const AnyString& query) { // note: mongoose does not provide the fragment here, so we don't have // to check it // Some tests are already done before calling this method assert(not query.empty()); String key; // temporary string for parameters handling uint offset = 0; uint start = 0; AnyString value; do { offset = query.find_first_of("=&", offset); if (offset >= query.size()) { // ignoring fields with empty value (using default) break; } if (query[offset] == '=') { key.assign(query, offset - start, start); if (key.empty()) // malformed url. aborting return false; ++offset; // FIXME !!!! & are not properly handled !!!!!!!!!!!! uint ampersand = offset; ampersand = query.find('&', ampersand); if (ampersand >= query.size()) { value.adapt(query, query.size() - offset, offset); ampersand = query.size(); } else value.adapt(query, ampersand - offset, offset); if (not value.empty()) { KeyValueStore::iterator i = params.find(key); if (i != params.end()) { // the item has been found ! params[key] = value; } } offset = ampersand; } else { // ignoring fields with empty value (using default) } // updating offsets start = ++offset; } while (true); return true; }
EventPropagation TextEditor::charInput(const AnyString& str) { switch (str[0]) { // Backspace case 0x08: for (uint i = 0; i < str.size(); ++i) { // Cannot use backspace when at beginning of file if (0 == pCursorPos.y && 1 == pCursorPos.x) return epStop; // When at beginning of line but not on first line, move up if (0 == pCursorPos.y && pCursorPos.x > 1) cursorPos(pCursorPos.x - 1, columnCount(pCursorPos.x - 1)); else cursorPos(pCursorPos.x, pCursorPos.y - 1); // Erase pText.erase(cursorToByte(pCursorPos), 1); } invalidate(); break; // Space case ' ': pText.insert(cursorToByte(pCursorPos), str); pCursorPos.x += str.size(); invalidate(); break; // Tab case '\t': pText.insert(cursorToByte(pCursorPos), str); cursorPos(pCursorPos.x, pCursorPos.y + str.size() * pTabWidth); invalidate(); break; // Carriage Return case '\r': // New Line / Line Feed case '\n': for (uint i = 0; i < str.size(); ++i) pText.insert(cursorToByte(pCursorPos), '\n'); pCursorPos.y += str.size(); invalidate(); break; // Normal displayable characters default: // Normal ASCII if ((uint8)str[0] < 0x80) { // Non-displayable characters are ignored std::locale loc; if (!std::isgraph(str[0], loc)) break; } pText.insert(cursorToByte(pCursorPos), str); // Advance the cursor pCursorPos.x += str.utf8size(); invalidate(); break; } return epStop; }
bool Resize(const AnyString& filename, uint64_t size) { if (not filename.empty()) { if (size < std::numeric_limits<off_t>::max()) { #ifndef YUNI_OS_WINDOWS { assert((filename.c_str())[filename.size()] == '\0'); #ifdef YUNI_OS_MAC int fd = open(filename.c_str(), O_WRONLY|O_CREAT, 0644); #else int fd = open(filename.c_str(), O_WRONLY|O_CREAT|O_LARGEFILE, 0644); #endif if (fd != -1) { bool success = (0 == ftruncate(fd, static_cast<off_t>(size))); close(fd); return success; } } #else { WString wstr(filename, true); if (not wstr.empty()) { HANDLE hndl = CreateFileW(wstr.c_str(), GENERIC_WRITE, FILE_SHARE_WRITE, NULL, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); if (hndl) { LARGE_INTEGER li; li.QuadPart = size; DWORD dwPtr = SetFilePointer(hndl, li.LowPart, &li.HighPart, FILE_BEGIN); if (dwPtr != INVALID_SET_FILE_POINTER) SetEndOfFile(hndl); CloseHandle(hndl); return true; } } } #endif } } return false; }