12
12
* Note: these can't be freed per thread, since
13
13
* DllMain(DLL_THREAD_ATTACH/DLL_THREAD_DETACH) is optional (and apps are
14
14
* inconsistent even calling attach-detach for same thread). */
15
- static wchar_t * * u16buffs = NULL ;
16
- static size_t u16buff_cnt = 0 ;
17
- static esodbc_mutex_lt u16buff_mux = ESODBC_MUX_SINIT ;
15
+ static void * * utf_buffs = NULL ;
16
+ static size_t utf_buff_cnt = 0 ;
17
+ static esodbc_mutex_lt utf_buff_mux = ESODBC_MUX_SINIT ;
18
18
19
19
/* advance an iterator of an "entered" JSON-sytle map to the value for the
20
20
* given key, if that exists */
@@ -189,31 +189,30 @@ CborError cbor_container_is_empty(CborValue cont, BOOL *empty)
189
189
return CborNoError ;
190
190
}
191
191
192
- static BOOL enlist_utf16_buffer ( wchar_t * old , wchar_t * new )
192
+ static BOOL enlist_utf_buffer ( void * old , void * new )
193
193
{
194
- wchar_t * * r ;
194
+ void * * r ;
195
195
size_t i ;
196
196
197
- if (! old ) {
198
- /* new entry must be inserted into list */
199
- ESODBC_MUX_LOCK (& u16buff_mux );
200
- r = realloc (u16buffs , (u16buff_cnt + 1 ) * sizeof (wchar_t * ));
197
+ if (! old ) { /* new entry must be inserted into list */
198
+ ESODBC_MUX_LOCK (& utf_buff_mux );
199
+ r = realloc (utf_buffs , (utf_buff_cnt + 1 ) * sizeof (void * ));
201
200
if (r ) {
202
- u16buffs = r ;
203
- u16buffs [ u16buff_cnt ++ ] = new ;
201
+ utf_buffs = r ;
202
+ utf_buffs [ utf_buff_cnt ++ ] = new ;
204
203
}
205
- ESODBC_MUX_UNLOCK (& u16buff_mux );
206
- } else {
207
- ESODBC_MUX_LOCK (& u16buff_mux );
204
+ ESODBC_MUX_UNLOCK (& utf_buff_mux );
205
+ } else { /* old entry has be reallocated, store its updated ref */
206
+ ESODBC_MUX_LOCK (& utf_buff_mux );
208
207
r = NULL ;
209
- for (i = 0 ; i < u16buff_cnt ; i ++ ) {
210
- if (u16buffs [i ] == old ) {
211
- r = & u16buffs [i ];
212
- u16buffs [i ] = new ;
208
+ for (i = 0 ; i < utf_buff_cnt ; i ++ ) {
209
+ if (utf_buffs [i ] == old ) {
210
+ r = & utf_buffs [i ];
211
+ utf_buffs [i ] = new ;
213
212
break ;
214
213
}
215
214
}
216
- ESODBC_MUX_UNLOCK (& u16buff_mux );
215
+ ESODBC_MUX_UNLOCK (& utf_buff_mux );
217
216
}
218
217
219
218
return !!r ;
@@ -222,31 +221,82 @@ static BOOL enlist_utf16_buffer(wchar_t *old, wchar_t *new)
222
221
void tinycbor_cleanup ()
223
222
{
224
223
size_t i ;
225
- for (i = 0 ; i < u16buff_cnt ; i ++ ) {
226
- free (u16buffs [i ]);
224
+ for (i = 0 ; i < utf_buff_cnt ; i ++ ) {
225
+ free (utf_buffs [i ]);
227
226
}
228
227
if (i ) {
229
- free (u16buffs );
228
+ free (utf_buffs );
230
229
}
231
230
}
232
231
232
+ static BOOL enlarge_buffer (void * str_ptr , size_t new_cnt , size_t usize )
233
+ {
234
+ wstr_st r ; /* reallocated */
235
+ wstr_st * wbuff = (wstr_st * )str_ptr ;
236
+ /* the two string struct types should remain identical (ptr, size_t),
237
+ * for the above cast to work also for cstr_st inputs */
238
+ assert (sizeof (cstr_st ) == sizeof (wstr_st ));
239
+ assert ((void * )wbuff -> str == (void * )((cstr_st * )str_ptr )-> str );
240
+ assert (wbuff -> cnt == ((cstr_st * )str_ptr )-> cnt );
241
+
242
+ /* double scratchpad size until exceeding min needed space.
243
+ * condition on equality, to allow for a 0-term */
244
+ for (r .cnt = (0 < wbuff -> cnt && wbuff -> cnt < (size_t )-1 ) ? wbuff -> cnt :
245
+ ESODBC_BODY_BUF_START_SIZE ; r .cnt <= new_cnt ; r .cnt *= 2 ) {
246
+ ;
247
+ }
248
+ if (! (r .str = realloc (wbuff -> str , r .cnt * usize ))) {
249
+ return false;
250
+ }
251
+ if (! enlist_utf_buffer (wbuff -> str , r .str )) {
252
+ /* it should only possibly fail on 1st allocation per-thread (since
253
+ * the rest of invocations are to swap the pointers) */
254
+ assert (! wbuff -> str );
255
+ free (r .str );
256
+ return false;
257
+ } else {
258
+ * wbuff = r ;
259
+ }
260
+ DBG ("new UTF conv. buffer @0x%p, size %zu, usize: %zu." , wbuff -> str ,
261
+ wbuff -> cnt , usize );
262
+ return true;
263
+ }
264
+
233
265
/* Fetches and converts a(n always UTF8) text string to UTF16 wide char.
234
266
* Uses a dynamically allocated thread-local buffer.
235
267
* 0-terminates the string */
236
268
CborError cbor_value_get_utf16_wstr (CborValue * it , wstr_st * utf16 )
237
269
{
270
+ /* .cnt needs to be non-zero, for U8MB_TO_U16WC() to fail on 1st invoc. */
238
271
static thread_local wstr_st wbuff = {.str = NULL , .cnt = (size_t )-1 };
239
- wstr_st r ; /* reallocated */
272
+ static thread_local cstr_st cbuff = { 0 };
240
273
cstr_st mb_str ; /* multibyte string */
241
274
CborError res ;
242
275
int n ;
276
+ size_t len ;
243
277
244
278
assert (cbor_value_is_text_string (it ));
245
279
/* get the multibyte string to convert */
246
- res = cbor_value_get_string_chunk (it , & mb_str .str , & mb_str .cnt );
247
- if (res != CborNoError ) {
248
- return res ;
280
+ if (cbor_value_is_length_known (it )) { /* str contained in single chunk? */
281
+ res = cbor_value_get_string_chunk (it , & mb_str .str , & mb_str .cnt );
282
+ if (res != CborNoError ) {
283
+ return res ;
284
+ }
285
+ } else { /* string is spread across multiple chunks */
286
+ res = cbor_value_calculate_string_length (it , & len );
287
+ if (res != CborNoError ) {
288
+ return res ;
289
+ }
290
+ if (cbuff .cnt <= len && !enlarge_buffer (& cbuff , len , sizeof (char ))) {
291
+ return CborErrorOutOfMemory ;
292
+ }
293
+ mb_str = cbuff ;
294
+ res = cbor_value_copy_text_string (it , mb_str .str , & mb_str .cnt , it );
295
+ if (res != CborNoError ) {
296
+ return res ;
297
+ }
249
298
}
299
+
250
300
/* attempt string conversion */
251
301
while ((n = U8MB_TO_U16WC (mb_str .str , mb_str .cnt , wbuff .str ,
252
302
wbuff .cnt )) <= 0 ) {
@@ -264,7 +314,6 @@ CborError cbor_value_get_utf16_wstr(CborValue *it, wstr_st *utf16)
264
314
} /* else: buffer hasn't yet been allocated or is too small */
265
315
/* what's the minimum space needed? */
266
316
if ((n = U8MB_TO_U16WC (mb_str .str , mb_str .cnt , NULL , 0 )) < 0 ) {
267
- TRACE ;
268
317
return CborErrorInvalidUtf8TextString ;
269
318
}
270
319
} else {
@@ -273,28 +322,13 @@ CborError cbor_value_get_utf16_wstr(CborValue *it, wstr_st *utf16)
273
322
break ;
274
323
}
275
324
}
276
- /* double scratchpad size until exceeding min needed space.
277
- * condition on equality, to allow for a 0-term */
278
- for (r .cnt = wbuff .cnt < (size_t )-1 ? wbuff .cnt :
279
- ESODBC_BODY_BUF_START_SIZE ; r .cnt <= (size_t )n ; r .cnt *= 2 ) {
280
- ;
281
- }
282
- if (! (r .str = realloc (wbuff .str , r .cnt ))) {
325
+ if (! enlarge_buffer (& wbuff , (size_t )n , sizeof (wchar_t ))) {
283
326
return CborErrorOutOfMemory ;
284
327
}
285
- if (! enlist_utf16_buffer (wbuff .str , r .str )) {
286
- /* it should only fail on 1st allocation per-thread */
287
- assert (! wbuff .str );
288
- free (r .str );
289
- return CborErrorOutOfMemory ;
290
- } else {
291
- wbuff = r ;
292
- }
293
- DBG ("new UTF8/16 conv. buffer @0x%p, size %zu." , wbuff .str , wbuff .cnt );
294
328
}
295
329
296
330
/* U8MB_TO_U16WC() will only convert the 0-term if counted in input*/
297
- wbuff .str [n ] = '\0' ; /* set, but not counted */
331
+ wbuff .str [n ] = L '\0' ; /* set, but not counted */
298
332
utf16 -> str = wbuff .str ;
299
333
utf16 -> cnt = n ;
300
334
return CborNoError ;
0 commit comments