1 
2 /*
3  * Copyright 2006 The Android Open Source Project
4  *
5  * Use of this source code is governed by a BSD-style license that can be
6  * found in the LICENSE file.
7  */
8 
9 
10 #include "SkTSearch.h"
11 #include <ctype.h>
12 
index_into_base(const char * const * base,int index,size_t elemSize)13 static inline const char* index_into_base(const char*const* base, int index,
14                                           size_t elemSize)
15 {
16     return *(const char*const*)((const char*)base + index * elemSize);
17 }
18 
SkStrSearch(const char * const * base,int count,const char target[],size_t target_len,size_t elemSize)19 int SkStrSearch(const char*const* base, int count, const char target[],
20                 size_t target_len, size_t elemSize)
21 {
22     if (count <= 0)
23         return ~0;
24 
25     SkASSERT(base != NULL);
26 
27     int lo = 0;
28     int hi = count - 1;
29 
30     while (lo < hi)
31     {
32         int mid = (hi + lo) >> 1;
33         const char* elem = index_into_base(base, mid, elemSize);
34 
35         int cmp = strncmp(elem, target, target_len);
36         if (cmp < 0)
37             lo = mid + 1;
38         else if (cmp > 0 || strlen(elem) > target_len)
39             hi = mid;
40         else
41             return mid;
42     }
43 
44     const char* elem = index_into_base(base, hi, elemSize);
45     int cmp = strncmp(elem, target, target_len);
46     if (cmp || strlen(elem) > target_len)
47     {
48         if (cmp < 0)
49             hi += 1;
50         hi = ~hi;
51     }
52     return hi;
53 }
54 
SkStrSearch(const char * const * base,int count,const char target[],size_t elemSize)55 int SkStrSearch(const char*const* base, int count, const char target[],
56                 size_t elemSize)
57 {
58     return SkStrSearch(base, count, target, strlen(target), elemSize);
59 }
60 
SkStrLCSearch(const char * const * base,int count,const char target[],size_t len,size_t elemSize)61 int SkStrLCSearch(const char*const* base, int count, const char target[],
62                   size_t len, size_t elemSize)
63 {
64     SkASSERT(target);
65 
66     SkAutoAsciiToLC tolc(target, len);
67 
68     return SkStrSearch(base, count, tolc.lc(), len, elemSize);
69 }
70 
SkStrLCSearch(const char * const * base,int count,const char target[],size_t elemSize)71 int SkStrLCSearch(const char*const* base, int count, const char target[],
72                   size_t elemSize)
73 {
74     return SkStrLCSearch(base, count, target, strlen(target), elemSize);
75 }
76 
77 //////////////////////////////////////////////////////////////////////////////
78 
SkAutoAsciiToLC(const char str[],size_t len)79 SkAutoAsciiToLC::SkAutoAsciiToLC(const char str[], size_t len)
80 {
81     // see if we need to compute the length
82     if ((long)len < 0) {
83         len = strlen(str);
84     }
85     fLength = len;
86 
87     // assign lc to our preallocated storage if len is small enough, or allocate
88     // it on the heap
89     char*   lc;
90     if (len <= STORAGE) {
91         lc = fStorage;
92     } else {
93         lc = (char*)sk_malloc_throw(len + 1);
94     }
95     fLC = lc;
96 
97     // convert any asii to lower-case. we let non-ascii (utf8) chars pass
98     // through unchanged
99     for (int i = (int)(len - 1); i >= 0; --i) {
100         int c = str[i];
101         if ((c & 0x80) == 0) {   // is just ascii
102             c = tolower(c);
103         }
104         lc[i] = c;
105     }
106     lc[len] = 0;
107 }
108 
~SkAutoAsciiToLC()109 SkAutoAsciiToLC::~SkAutoAsciiToLC()
110 {
111     if (fLC != fStorage) {
112         sk_free(fLC);
113     }
114 }
115