summaryrefslogtreecommitdiff
path: root/src/pal/src/include/pal/stackstring.hpp
blob: 133ec4a05e117517ee5c4477623be7c7c6212c94 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.

#ifndef __STACKSTRING_H_
#define __STACKSTRING_H_

template <SIZE_T STACKCOUNT, class T>
class StackString
{
private:
    T m_innerBuffer[STACKCOUNT + 1];
    T * m_buffer;
    SIZE_T m_size; // actual allocated size
    SIZE_T m_count; // actual length of string

    void NullTerminate()
    {
        m_buffer[m_count] = 0;
    }

    void DeleteBuffer()
    {
        if (m_innerBuffer != m_buffer)
            PAL_free(m_buffer);

        m_buffer = NULL;
        return;
    }

    BOOL ReallocateBuffer(SIZE_T count)
    {
        // count is always > STACKCOUNT here.
        // We got so far, we will allocate a little extra
        // to prevent frequent allocations
#if _DEBUG
        SIZE_T count_allocated = count;
#else
        SIZE_T count_allocated = count + 100;
#endif //_DEBUG

        BOOL dataOnStack =  m_buffer == m_innerBuffer;
        if( dataOnStack )
        {
            m_buffer = NULL;
        }

        T * newBuffer = (T *)PAL_realloc(m_buffer, (count_allocated + 1) * sizeof(T));
        if (NULL == newBuffer)
        {
            SetLastError(ERROR_NOT_ENOUGH_MEMORY);

            DeleteBuffer();
            m_count = 0;
            m_buffer = m_innerBuffer;
            return FALSE;
        }

        if( dataOnStack)
        {
            CopyMemory(newBuffer, m_innerBuffer, (m_count + 1) * sizeof(T));
        }

        m_buffer = newBuffer;
        m_count = count;
        m_size = count_allocated + 1;

        return TRUE;
    }
    
    BOOL HasAvailableMemory(SIZE_T count)
    {
        return (count < m_size);
    }

    //NOTE: Always call this before modifying the underlying buffer
    BOOL Resize(SIZE_T count)
    {

        if (NULL == m_buffer)
        {
            m_buffer = m_innerBuffer;
        }
        
        if (HasAvailableMemory(count))
        {
            m_count = count;
        }
        else 
        {
            if (count > STACKCOUNT)
            {
                return ReallocateBuffer(count);
            }
            else
            {
                m_count = count;
                m_size = STACKCOUNT+1;
            }
        }

        return TRUE;
    }

    StackString(const StackString &s)
    {
        Set(s);
    }

public:
    StackString()
        : m_buffer(m_innerBuffer), m_size(STACKCOUNT+1), m_count(0)
    {
    }


    BOOL Set(const T * buffer, SIZE_T count)
    {
        if (!Resize(count))
            return FALSE;

        CopyMemory(m_buffer, buffer, (count + 1) * sizeof(T));
        NullTerminate();
        return TRUE;
    }

    BOOL Set(const StackString &s)
    {
        return Set(s.m_buffer, s.m_count);
    }

    template<SIZE_T bufferLength> BOOL Set(const T (&buffer)[bufferLength])
    {
        // bufferLength includes terminator character
        return Set(buffer, bufferLength - 1);
    }

    SIZE_T GetCount() const
    {
        return m_count;
    }
    
    SIZE_T GetSizeOf() const
    {
        return m_size * sizeof(T);
    }

    CONST T * GetString() const
    {
        return (const T *)m_buffer;
    }

    operator const T * () const {  return GetString(); }

    //Always preserves the existing content
    T * OpenStringBuffer(SIZE_T count)
    {
        T * result = NULL;
        if (Resize(count))
        {
            result = (T *)m_buffer;
        }
        return result;
    }

    T * OpenStringBuffer()
    {
        return m_buffer;
    }

    //count should not include the terminating null
    void CloseBuffer(SIZE_T count)
    {
        if (m_count > count)
            m_count = count;

        NullTerminate();
        return;
    }
    
    //Call this with the best estimate if you want to
    //prevent possible reallocations on further operations 
    BOOL Reserve(SIZE_T count)
    {
        SIZE_T endpos = m_count;
        
        if (!Resize(count))
            return FALSE;

        m_count = endpos;
        NullTerminate();

        return TRUE;
    }

    //count Should not include the terminating null
    BOOL Append(const T * buffer, SIZE_T count)
    {
        SIZE_T endpos = m_count;
        if (!Resize(m_count + count))
            return FALSE;

        CopyMemory(&m_buffer[endpos], buffer, (count + 1) * sizeof(T));
        NullTerminate();
        return TRUE;
    }

    BOOL Append(const StackString &s)
    {
        return Append(s.GetString(), s.GetCount());
    }

    template<SIZE_T bufferLength> BOOL Append(const T (&buffer)[bufferLength])
    {
        // bufferLength includes terminator character
        return Append(buffer, bufferLength - 1);
    }

    BOOL Append(T ch)
    {
        SIZE_T endpos = m_count;
        if (!Resize(m_count + 1))
            return FALSE;

        m_buffer[endpos] = ch;
        NullTerminate();
        return TRUE;
    }

    BOOL IsEmpty()
    {
        return 0 == m_buffer[0];
    }

    void Clear()
    {
        m_count = 0;
        NullTerminate();
    }

    ~StackString()
    {
        DeleteBuffer();
    }
};

#if _DEBUG
typedef StackString<32, CHAR> PathCharString;
typedef StackString<32, WCHAR> PathWCharString; 
#else
typedef StackString<MAX_PATH, CHAR> PathCharString;
typedef StackString<MAX_PATH, WCHAR> PathWCharString; 
#endif
#endif

// Some Helper Definitions
BOOL 
PAL_GetPALDirectoryW(
        PathWCharString& lpDirectoryName);
BOOL 
PAL_GetPALDirectoryA(
        PathCharString& lpDirectoryName);
DWORD
GetCurrentDirectoryA(
         PathCharString& lpBuffer);
void 
FILEDosToUnixPathA(
        PathCharString& lpPath);