xref: /core/sal/rtl/ustrbuf.cxx (revision 5a3bb76c)
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3  * This file is part of the LibreOffice project.
4  *
5  * This Source Code Form is subject to the terms of the Mozilla Public
6  * License, v. 2.0. If a copy of the MPL was not distributed with this
7  * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8  *
9  * This file incorporates work covered by the following license notice:
10  *
11  *   Licensed to the Apache Software Foundation (ASF) under one or more
12  *   contributor license agreements. See the NOTICE file distributed
13  *   with this work for additional information regarding copyright
14  *   ownership. The ASF licenses this file to you under the Apache
15  *   License, Version 2.0 (the "License"); you may not use this file
16  *   except in compliance with the License. You may obtain a copy of
17  *   the License at http://www.apache.org/licenses/LICENSE-2.0 .
18  */
19 
20 #include <string.h>
21 
22 #include <osl/interlck.h>
23 #include <osl/diagnose.h>
24 #include <rtl/character.hxx>
25 #include <rtl/ustrbuf.hxx>
26 #include "strimp.hxx"
27 
28 #if USE_SDT_PROBES
29 #define RTL_LOG_STRING_BITS         16
30 #endif
31 
32 void SAL_CALL rtl_uStringbuffer_newFromStr_WithLength( rtl_uString ** newStr,
33                                                        const sal_Unicode * value,
34                                                        sal_Int32 count)
35 {
36     assert(newStr);
37     assert(count >= 0);
38     if (!value)
39     {
40         rtl_uString_new_WithLength( newStr, 16 );
41         return;
42     }
43 
44     rtl_uString_new_WithLength( newStr, count + 16 );
45     (*newStr)->length = count;
46     memcpy( (*newStr)->buffer, value, count * sizeof(sal_Unicode));
47     RTL_LOG_STRING_NEW( *newStr );
48 }
49 
50 rtl_uString * SAL_CALL rtl_uStringBuffer_refReturn( rtl_uString * pThis )
51 {
52     RTL_LOG_STRING_NEW( pThis );
53     rtl_uString_acquire( pThis );
54     return pThis;
55 }
56 
57 rtl_uString * SAL_CALL rtl_uStringBuffer_makeStringAndClear( rtl_uString ** ppThis,
58                                                              sal_Int32 *nCapacity )
59 {
60     assert(ppThis);
61     assert(nCapacity);
62     // avoid an un-necessary atomic ref/unref pair
63     rtl_uString *pStr = *ppThis;
64     *ppThis = nullptr;
65 
66     rtl_uString_new (ppThis);
67     *nCapacity = 0;
68 
69     RTL_LOG_STRING_NEW( pStr );
70 
71     return pStr;
72 }
73 
74 sal_Int32 SAL_CALL rtl_uStringbuffer_newFromStringBuffer( rtl_uString ** newStr,
75                                                           sal_Int32 capacity,
76                                                           rtl_uString * oldStr )
77 {
78     assert(newStr);
79     assert(capacity >= 0);
80     assert(oldStr);
81     sal_Int32 newCapacity = capacity;
82 
83     if (newCapacity < oldStr->length)
84         newCapacity = oldStr->length;
85 
86     rtl_uString_new_WithLength( newStr, newCapacity );
87 
88     if (oldStr->length > 0) {
89         (*newStr)->length = oldStr->length;
90         memcpy( (*newStr)->buffer, oldStr->buffer, oldStr->length * sizeof(sal_Unicode));
91     }
92     RTL_LOG_STRING_NEW( *newStr );
93     return newCapacity;
94 }
95 
96 void SAL_CALL rtl_uStringbuffer_ensureCapacity
97     (rtl_uString ** This, sal_Int32* capacity, sal_Int32 minimumCapacity)
98 {
99     assert(This);
100     assert(capacity && *capacity >= 0);
101     assert(minimumCapacity >= 0);
102     if (minimumCapacity > *capacity)
103     {
104         rtl_uString * pTmp = *This;
105         rtl_uString * pNew = nullptr;
106         *capacity = ((*This)->length + 1) * 2;
107         if (minimumCapacity > *capacity)
108             /* still lower, set to the minimum capacity */
109             *capacity = minimumCapacity;
110 
111         rtl_uString_new_WithLength(&pNew, *capacity);
112         pNew->length = (*This)->length;
113         *This = pNew;
114 
115         memcpy( (*This)->buffer, pTmp->buffer, pTmp->length * sizeof(sal_Unicode) );
116 
117         RTL_LOG_STRING_NEW( pTmp ); // with accurate contents
118         rtl_uString_release( pTmp );
119     }
120 }
121 
122 void SAL_CALL rtl_uStringbuffer_insert( rtl_uString ** This,
123                                         sal_Int32 * capacity,
124                                         sal_Int32 offset,
125                                         const sal_Unicode * str,
126                                         sal_Int32 len)
127 {
128     assert(This);
129     assert(capacity && *capacity >= 0);
130     assert(offset >= 0 && offset <= (**This).length);
131     assert(len >= 0);
132     sal_Int32 nOldLen;
133     sal_Unicode * pBuf;
134     sal_Int32 n;
135     if( len != 0 )
136     {
137         if (*capacity < (*This)->length + len)
138             rtl_uStringbuffer_ensureCapacity( This, capacity, (*This)->length + len );
139 
140         nOldLen = (*This)->length;
141         pBuf = (*This)->buffer;
142 
143         /* copy the tail */
144         n = (nOldLen - offset);
145         if( n == 1 )
146                             /* optimized for 1 character */
147             pBuf[offset + len] = pBuf[offset];
148         else if( n > 1 )
149             memmove( pBuf + offset + len, pBuf + offset, n * sizeof(sal_Unicode) );
150 
151         /* insert the new characters */
152         if( str != nullptr )
153         {
154             if( len == 1 )
155                 /* optimized for 1 character */
156                 pBuf[offset] = *str;
157             else
158                 memcpy( pBuf + offset, str, len * sizeof(sal_Unicode) );
159         }
160         (*This)->length = nOldLen + len;
161         pBuf[ nOldLen + len ] = 0;
162     }
163 }
164 
165 void rtl_uStringbuffer_insertUtf32(
166     rtl_uString ** pThis, sal_Int32 * capacity, sal_Int32 offset, sal_uInt32 c)
167     SAL_THROW_EXTERN_C()
168 {
169     sal_Unicode buf[2];
170     sal_Int32 len;
171     OSL_ASSERT(rtl::isUnicodeScalarValue(c));
172     if (c <= 0xFFFF) {
173         buf[0] = static_cast<sal_Unicode>(c);
174         len = 1;
175     } else {
176         c -= 0x10000;
177         buf[0] = static_cast<sal_Unicode>((c >> 10) | 0xD800);
178         buf[1] = static_cast<sal_Unicode>((c & 0x3FF) | 0xDC00);
179         len = 2;
180     }
181     rtl_uStringbuffer_insert(pThis, capacity, offset, buf, len);
182 }
183 
184 void SAL_CALL rtl_uStringbuffer_insert_ascii(   /*inout*/rtl_uString ** This,
185                                                 /*inout*/sal_Int32 * capacity,
186                                                 sal_Int32 offset,
187                                                 const sal_Char * str,
188                                                 sal_Int32 len)
189 {
190     assert(This);
191     assert(capacity && *capacity >= 0);
192     assert(offset >= 0 && offset <= (**This).length);
193     assert(len == 0 || str != nullptr);
194     assert(len >= 0);
195     sal_Int32 nOldLen;
196     sal_Unicode * pBuf;
197     sal_Int32 n;
198     if( len != 0 )
199     {
200         if (*capacity < (*This)->length + len)
201             rtl_uStringbuffer_ensureCapacity( This, capacity, (*This)->length + len );
202 
203         nOldLen = (*This)->length;
204         pBuf = (*This)->buffer;
205 
206         /* copy the tail */
207         n = (nOldLen - offset);
208         if( n == 1 )
209             /* optimized for 1 character */
210             pBuf[offset + len] = pBuf[offset];
211         else if( n > 1 )
212             memmove( pBuf + offset + len, pBuf + offset, n * sizeof(sal_Unicode) );
213 
214         /* insert the new characters */
215         for( n = 0; n < len; n++ )
216         {
217             /* Check ASCII range */
218             OSL_ENSURE( (*str & 0x80) == 0, "Found ASCII char > 127");
219 
220             pBuf[offset + n] = static_cast<sal_Unicode>(*(str++));
221         }
222 
223         (*This)->length = nOldLen + len;
224         pBuf[ nOldLen + len ] = 0;
225     }
226 }
227 
228 /*************************************************************************
229  *  rtl_uStringbuffer_remove
230  */
231 void SAL_CALL rtl_uStringbuffer_remove( rtl_uString ** This,
232                                        sal_Int32 start,
233                                        sal_Int32 len )
234 {
235     assert(This);
236     assert(start >= 0 && start <= (**This).length);
237     assert(len >= 0);
238     sal_Int32 nTailLen;
239     sal_Unicode * pBuf;
240 
241     if (len > (*This)->length - start)
242         len = (*This)->length - start;
243 
244     //remove nothing
245     if (!len)
246         return;
247 
248     pBuf = (*This)->buffer;
249     nTailLen = (*This)->length - ( start + len );
250 
251     if (nTailLen)
252     {
253         /* move the tail */
254         memmove(pBuf + start, pBuf + start + len, nTailLen * sizeof(sal_Unicode));
255     }
256 
257     (*This)->length-=len;
258     pBuf[ (*This)->length ] = 0;
259 }
260 
261 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
262