1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 #include "chrome/installer/mini_installer/mini_string.h" 6 7 #include <windows.h> 8 9 namespace { 10 11 // Returns true if the given two ASCII characters are same (ignoring case). 12 bool EqualASCIICharI(wchar_t a, wchar_t b) { 13 if (a >= L'A' && a <= L'Z') 14 a += (L'a' - L'A'); 15 if (b >= L'A' && b <= L'Z') 16 b += (L'a' - L'A'); 17 return (a == b); 18 } 19 20 } // namespace 21 22 namespace mini_installer { 23 24 // Formats a sequence of |bytes| as hex. The |str| buffer must have room for 25 // at least 2*|size| + 1. 26 bool HexEncode(const void* bytes, size_t size, wchar_t* str, size_t str_size) { 27 if (str_size <= (size * 2)) 28 return false; 29 30 static const wchar_t kHexChars[] = L"0123456789ABCDEF"; 31 32 str[size * 2] = L'\0'; 33 34 for (size_t i = 0; i < size; ++i) { 35 char b = reinterpret_cast<const char*>(bytes)[i]; 36 str[(i * 2)] = kHexChars[(b >> 4) & 0xf]; 37 str[(i * 2) + 1] = kHexChars[b & 0xf]; 38 } 39 40 return true; 41 } 42 43 size_t SafeStrLen(const wchar_t* str, size_t alloc_size) { 44 if (!str || !alloc_size) 45 return 0; 46 size_t len = 0; 47 while (--alloc_size && str[len] != L'\0') 48 ++len; 49 return len; 50 } 51 52 bool SafeStrCopy(wchar_t* dest, size_t dest_size, const wchar_t* src) { 53 if (!dest || !dest_size) 54 return false; 55 56 wchar_t* write = dest; 57 for (size_t remaining = dest_size; remaining != 0; --remaining) { 58 if ((*write++ = *src++) == L'\0') 59 return true; 60 } 61 62 // If we fail, we do not want to leave the string with partially copied 63 // contents. The reason for this is that we use these strings mostly for 64 // named objects such as files. If we copy a partial name, then that could 65 // match with something we do not want it to match with. 66 // Furthermore, since SafeStrCopy is called from SafeStrCat, we do not 67 // want to mutate the string in case the caller handles the error of a 68 // failed concatenation. For example: 69 // 70 // wchar_t buf[5] = {0}; 71 // if (!SafeStrCat(buf, arraysize(buf), kLongName)) 72 // SafeStrCat(buf, arraysize(buf), kShortName); 73 // 74 // If we were to return false in the first call to SafeStrCat but still 75 // mutate the buffer, the buffer will be in an unexpected state. 76 *dest = L'\0'; 77 return false; 78 } 79 80 // Safer replacement for lstrcat function. 81 bool SafeStrCat(wchar_t* dest, size_t dest_size, const wchar_t* src) { 82 // Use SafeStrLen instead of lstrlen just in case the |dest| buffer isn't 83 // terminated. 84 int str_len = SafeStrLen(dest, dest_size); 85 return SafeStrCopy(dest + str_len, dest_size - str_len, src); 86 } 87 88 bool StrEndsWith(const wchar_t* str, const wchar_t* end_str) { 89 if (str == NULL || end_str == NULL) 90 return false; 91 92 for (int i = lstrlen(str) - 1, j = lstrlen(end_str) - 1; j >= 0; --i, --j) { 93 if (i < 0 || !EqualASCIICharI(str[i], end_str[j])) 94 return false; 95 } 96 97 return true; 98 } 99 100 bool StrStartsWith(const wchar_t* str, const wchar_t* start_str) { 101 if (str == NULL || start_str == NULL) 102 return false; 103 104 for (int i = 0; start_str[i] != L'\0'; ++i) { 105 if (!EqualASCIICharI(str[i], start_str[i])) 106 return false; 107 } 108 109 return true; 110 } 111 112 const wchar_t* SearchStringI(const wchar_t* source, const wchar_t* find) { 113 if (!find || find[0] == L'\0') 114 return source; 115 116 const wchar_t* scan = source; 117 while (*scan) { 118 const wchar_t* s = scan; 119 const wchar_t* f = find; 120 121 while (*s && *f && EqualASCIICharI(*s, *f)) 122 ++s, ++f; 123 124 if (!*f) 125 return scan; 126 127 ++scan; 128 } 129 130 return NULL; 131 } 132 133 bool FindTagInStr(const wchar_t* str, 134 const wchar_t* tag, 135 const wchar_t** position) { 136 int tag_length = ::lstrlen(tag); 137 const wchar_t* scan = str; 138 for (const wchar_t* tag_start = SearchStringI(scan, tag); 139 tag_start != NULL; 140 tag_start = SearchStringI(scan, tag)) { 141 scan = tag_start + tag_length; 142 if (*scan == L'-' || *scan == L'\0') { 143 if (position != NULL) 144 *position = tag_start; 145 return true; 146 } 147 } 148 return false; 149 } 150 151 wchar_t* GetNameFromPathExt(wchar_t* path, size_t size) { 152 if (size <= 1) 153 return NULL; 154 155 wchar_t* current = &path[size - 1]; 156 while (current != path && L'\\' != *current) 157 --current; 158 159 return (current == path) ? NULL : (current + 1); 160 } 161 162 } // namespace mini_installer 163