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).
EqualASCIICharI(wchar_t a,wchar_t b)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.
HexEncode(const void * bytes,size_t size,wchar_t * str,size_t str_size)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
SafeStrLen(const wchar_t * str,size_t alloc_size)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
SafeStrCopy(wchar_t * dest,size_t dest_size,const wchar_t * src)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.
SafeStrCat(wchar_t * dest,size_t dest_size,const wchar_t * src)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
StrEndsWith(const wchar_t * str,const wchar_t * end_str)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
StrStartsWith(const wchar_t * str,const wchar_t * start_str)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
SearchStringI(const wchar_t * source,const wchar_t * find)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
FindTagInStr(const wchar_t * str,const wchar_t * tag,const wchar_t ** position)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
GetNameFromPathExt(wchar_t * path,size_t size)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