// Copyright (c) 2011 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #include "chrome/installer/mini_installer/mini_string.h" #include <windows.h> namespace { // Returns true if the given two ASCII characters are same (ignoring case). bool EqualASCIICharI(wchar_t a, wchar_t b) { if (a >= L'A' && a <= L'Z') a += (L'a' - L'A'); if (b >= L'A' && b <= L'Z') b += (L'a' - L'A'); return (a == b); } } // namespace namespace mini_installer { // Formats a sequence of |bytes| as hex. The |str| buffer must have room for // at least 2*|size| + 1. bool HexEncode(const void* bytes, size_t size, wchar_t* str, size_t str_size) { if (str_size <= (size * 2)) return false; static const wchar_t kHexChars[] = L"0123456789ABCDEF"; str[size * 2] = L'\0'; for (size_t i = 0; i < size; ++i) { char b = reinterpret_cast<const char*>(bytes)[i]; str[(i * 2)] = kHexChars[(b >> 4) & 0xf]; str[(i * 2) + 1] = kHexChars[b & 0xf]; } return true; } size_t SafeStrLen(const wchar_t* str, size_t alloc_size) { if (!str || !alloc_size) return 0; size_t len = 0; while (--alloc_size && str[len] != L'\0') ++len; return len; } bool SafeStrCopy(wchar_t* dest, size_t dest_size, const wchar_t* src) { if (!dest || !dest_size) return false; wchar_t* write = dest; for (size_t remaining = dest_size; remaining != 0; --remaining) { if ((*write++ = *src++) == L'\0') return true; } // If we fail, we do not want to leave the string with partially copied // contents. The reason for this is that we use these strings mostly for // named objects such as files. If we copy a partial name, then that could // match with something we do not want it to match with. // Furthermore, since SafeStrCopy is called from SafeStrCat, we do not // want to mutate the string in case the caller handles the error of a // failed concatenation. For example: // // wchar_t buf[5] = {0}; // if (!SafeStrCat(buf, arraysize(buf), kLongName)) // SafeStrCat(buf, arraysize(buf), kShortName); // // If we were to return false in the first call to SafeStrCat but still // mutate the buffer, the buffer will be in an unexpected state. *dest = L'\0'; return false; } // Safer replacement for lstrcat function. bool SafeStrCat(wchar_t* dest, size_t dest_size, const wchar_t* src) { // Use SafeStrLen instead of lstrlen just in case the |dest| buffer isn't // terminated. int str_len = SafeStrLen(dest, dest_size); return SafeStrCopy(dest + str_len, dest_size - str_len, src); } bool StrEndsWith(const wchar_t* str, const wchar_t* end_str) { if (str == NULL || end_str == NULL) return false; for (int i = lstrlen(str) - 1, j = lstrlen(end_str) - 1; j >= 0; --i, --j) { if (i < 0 || !EqualASCIICharI(str[i], end_str[j])) return false; } return true; } bool StrStartsWith(const wchar_t* str, const wchar_t* start_str) { if (str == NULL || start_str == NULL) return false; for (int i = 0; start_str[i] != L'\0'; ++i) { if (!EqualASCIICharI(str[i], start_str[i])) return false; } return true; } const wchar_t* SearchStringI(const wchar_t* source, const wchar_t* find) { if (!find || find[0] == L'\0') return source; const wchar_t* scan = source; while (*scan) { const wchar_t* s = scan; const wchar_t* f = find; while (*s && *f && EqualASCIICharI(*s, *f)) ++s, ++f; if (!*f) return scan; ++scan; } return NULL; } bool FindTagInStr(const wchar_t* str, const wchar_t* tag, const wchar_t** position) { int tag_length = ::lstrlen(tag); const wchar_t* scan = str; for (const wchar_t* tag_start = SearchStringI(scan, tag); tag_start != NULL; tag_start = SearchStringI(scan, tag)) { scan = tag_start + tag_length; if (*scan == L'-' || *scan == L'\0') { if (position != NULL) *position = tag_start; return true; } } return false; } wchar_t* GetNameFromPathExt(wchar_t* path, size_t size) { if (size <= 1) return NULL; wchar_t* current = &path[size - 1]; while (current != path && L'\\' != *current) --current; return (current == path) ? NULL : (current + 1); } } // namespace mini_installer