GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: gx_system_private_string.c Lines: 151 151 100.0 %
Date: 2024-12-05 08:52:37 Branches: 96 96 100.0 %

Line Branch Exec Source
1
/***************************************************************************
2
 * Copyright (c) 2024 Microsoft Corporation
3
 *
4
 * This program and the accompanying materials are made available under the
5
 * terms of the MIT License which is available at
6
 * https://opensource.org/licenses/MIT.
7
 *
8
 * SPDX-License-Identifier: MIT
9
 **************************************************************************/
10
11
12
/**************************************************************************/
13
/**************************************************************************/
14
/**                                                                       */
15
/** GUIX Component                                                        */
16
/**                                                                       */
17
/**   Prompt Management (Prompt)                                          */
18
/**                                                                       */
19
/**************************************************************************/
20
21
#define GX_SOURCE_CODE
22
23
24
/* Include necessary system files.  */
25
#include "gx_api.h"
26
#include "gx_system.h"
27
#include "gx_utility.h"
28
29
/**************************************************************************/
30
/*                                                                        */
31
/*  FUNCTION                                               RELEASE        */
32
/*                                                                        */
33
/*    _gx_system_private_string_copy                      PORTABLE C      */
34
/*                                                           6.1          */
35
/*  AUTHOR                                                                */
36
/*                                                                        */
37
/*    Kenneth Maxwell, Microsoft Corporation                              */
38
/*                                                                        */
39
/*  DESCRIPTION                                                           */
40
/*                                                                        */
41
/*    This service makes a private copy of text assigned to a widget.     */
42
/*                                                                        */
43
/*                                                                        */
44
/*  INPUT                                                                 */
45
/*                                                                        */
46
/*    string                                Address of widget's text      */
47
/*                                            pointer                     */
48
/*    text                                  Pointer to string             */
49
/*                                                                        */
50
/*  OUTPUT                                                                */
51
/*                                                                        */
52
/*    status                                Completion status             */
53
/*                                                                        */
54
/*  CALLS                                                                 */
55
/*                                                                        */
56
/*    _gx_utility_string_length_check       Test string length            */
57
/*    _gx_system_memory_allocator           Allocate dynamic memory       */
58
/*    _gx_system_memory_free                Deallocate dynamic memory     */
59
/*                                                                        */
60
/*  CALLED BY                                                             */
61
/*                                                                        */
62
/*    GUIX internal code                                                  */
63
/*                                                                        */
64
/*  RELEASE HISTORY                                                       */
65
/*                                                                        */
66
/*    DATE              NAME                      DESCRIPTION             */
67
/*                                                                        */
68
/*  05-19-2020     Kenneth Maxwell          Initial Version 6.0           */
69
/*  09-30-2020     Kenneth Maxwell          Modified comment(s),          */
70
/*                                            resulting in version 6.1    */
71
/*                                                                        */
72
/**************************************************************************/
73
46
UINT _gx_system_private_string_copy(GX_STRING *string, GX_CONST GX_STRING *text)
74
{
75
GX_UBYTE *byte;
76
USHORT    current_buffer_size;
77
USHORT    needed_buffer_size;
78
79
46
    if (_gx_system_memory_allocator == GX_NULL)
80
    {
81
4
        string -> gx_string_ptr = GX_NULL;
82
4
        string -> gx_string_length = 0;
83
4
        return GX_SYSTEM_MEMORY_ERROR;
84
    }
85
86
    /* are we assigning a non-NULL string? */
87

42
    if (text && text -> gx_string_ptr)
88
    {
89
35
        GX_UTILITY_USHORT_CHECK(text -> gx_string_length)
90
34
        GX_UTILITY_MATH_USHORT_ADD((USHORT)text -> gx_string_length, 3, needed_buffer_size)
91
    }
92
    else
93
    {
94
7
        needed_buffer_size = 0;
95
    }
96
97
40
    if (needed_buffer_size)
98
    {
99
        /* check to see if we have already allocated sufficient memory */
100
33
        if (string -> gx_string_ptr)
101
        {
102
7
            byte = (GX_UBYTE *)string -> gx_string_ptr;
103
7
            current_buffer_size = *byte++;
104
7
            current_buffer_size = (USHORT)(current_buffer_size << 8);
105
7
            current_buffer_size = (USHORT)(current_buffer_size | (*byte++));
106
107
7
            if (current_buffer_size < needed_buffer_size)
108
            {
109
                /* if our buffer is not large enough, free the current buffer */
110
4
                _gx_system_memory_free((void *)string -> gx_string_ptr);
111
112
                /* and attempt to allocate a new buffer */
113
4
                string -> gx_string_ptr = (GX_CHAR *)_gx_system_memory_allocator(needed_buffer_size);
114
115
                /* if buffer allocation succeeded, update our buffer size and copy the string */
116
4
                if (string -> gx_string_ptr)
117
                {
118
3
                    byte = (GX_UBYTE *)string -> gx_string_ptr;
119
3
                    *byte++ = (GX_UBYTE)(needed_buffer_size >> 8);
120
3
                    *byte++ = (GX_UBYTE)(needed_buffer_size & 0xff);
121
122
3
                    memcpy(byte, text -> gx_string_ptr, text -> gx_string_length + 1); /* Use case of memcpy is verified. */
123
3
                    string -> gx_string_length = text -> gx_string_length;
124
                }
125
                else
126
                {
127
1
                    string -> gx_string_length = 0;
128
                }
129
            }
130
            else
131
            {
132
                /* the existing buffer is large enough, just copy the string without updating buffer size */
133
3
                memcpy(byte, text -> gx_string_ptr, text -> gx_string_length + 1); /* Use case of memcpy is verified. */
134
3
                string -> gx_string_length = text -> gx_string_length;
135
            }
136
        }
137
        else
138
        {
139
            /* the current buffer is NULL, attempt to allocate a new buffer */
140
26
            string -> gx_string_ptr = (GX_CHAR *)_gx_system_memory_allocator(needed_buffer_size);
141
142
            /* if buffer allocation succeeded, update our buffer size and copy the string */
143
26
            if (string -> gx_string_ptr)
144
            {
145
25
                byte = (GX_UBYTE *)string -> gx_string_ptr;
146
25
                *byte++ = (GX_UBYTE)(needed_buffer_size >> 8);
147
25
                *byte++ = (GX_UBYTE)(needed_buffer_size & 0xff);
148
149
25
                memcpy(byte, text -> gx_string_ptr, text -> gx_string_length + 1); /* Use case of memcpy is verified. */
150
25
                string -> gx_string_length = text -> gx_string_length;
151
            }
152
            else
153
            {
154
1
                string -> gx_string_length = 0;
155
            }
156
        }
157
    }
158
    else
159
    {
160
        /* here if the new text is GX_NULL, free our buffer if one has been allocated */
161
7
        if (string -> gx_string_ptr)
162
        {
163
1
            _gx_system_memory_free((void *)string -> gx_string_ptr);
164
1
            string -> gx_string_ptr = GX_NULL;
165
        }
166
167
7
        string -> gx_string_length = 0;
168
7
        return GX_SUCCESS;
169
    }
170
33
    if (string -> gx_string_ptr)
171
    {
172
31
        return(GX_SUCCESS);
173
    }
174
2
    return GX_SYSTEM_MEMORY_ERROR;
175
}
176
177
/**************************************************************************/
178
/*                                                                        */
179
/*  FUNCTION                                               RELEASE        */
180
/*                                                                        */
181
/*    _gx_system_private_string_list_copy                 PORTABLE C      */
182
/*                                                           6.1          */
183
/*  AUTHOR                                                                */
184
/*                                                                        */
185
/*    Kenneth Maxwell, Microsoft Corporation                              */
186
/*                                                                        */
187
/*  DESCRIPTION                                                           */
188
/*                                                                        */
189
/*    This service makes a private copy of string list assigned to a      */
190
/*    widget.                                                             */
191
/*                                                                        */
192
/*                                                                        */
193
/*  INPUT                                                                 */
194
/*                                                                        */
195
/*    ptr_address                           Address of widget's string    */
196
/*                                            list pointer                */
197
/*    string_list                           Pointer to string list        */
198
/*    string_count                          Number of string in list      */
199
/*                                                                        */
200
/*  OUTPUT                                                                */
201
/*                                                                        */
202
/*    status                                Completion status             */
203
/*                                                                        */
204
/*  CALLS                                                                 */
205
/*                                                                        */
206
/*    _gx_utility_string_length_check       Test string length            */
207
/*    _gx_system_memory_allocator           Allocate dynamic memory       */
208
/*    _gx_system_memory_free                Deallocate dynamic memory     */
209
/*                                                                        */
210
/*  CALLED BY                                                             */
211
/*                                                                        */
212
/*    GUIX internal code                                                  */
213
/*                                                                        */
214
/*  RELEASE HISTORY                                                       */
215
/*                                                                        */
216
/*    DATE              NAME                      DESCRIPTION             */
217
/*                                                                        */
218
/*  05-19-2020     Kenneth Maxwell          Initial Version 6.0           */
219
/*  09-30-2020     Kenneth Maxwell          Modified comment(s),          */
220
/*                                            resulting in version 6.1    */
221
/*                                                                        */
222
/**************************************************************************/
223
#if defined(GX_ENABLE_DEPRECATED_STRING_API)
224
22
UINT _gx_system_private_string_list_copy(GX_CONST GX_CHAR ***ptr_address, GX_CONST GX_CHAR **string_list, INT string_count)
225
{
226
UINT      status;
227
GX_UBYTE *byte;
228
USHORT    current_buffer_size;
229
USHORT    needed_buffer_size;
230
INT       index;
231
GX_CHAR **list_ptr;
232
GX_CHAR  *string_ptr;
233
UINT      length;
234
235
22
    list_ptr = (GX_CHAR **)*ptr_address;
236
237
22
    if (_gx_system_memory_allocator == GX_NULL)
238
    {
239
1
        *ptr_address = GX_NULL;
240
1
        return GX_SYSTEM_MEMORY_ERROR;
241
    }
242
243
    /* are we assigning a non-NULL string array? */
244
21
    if (string_list)
245
    {
246
        /* calculate size of needed buffer. buffer size for holding each string pointer +
247
                                            2 byte size +
248
                                            buffer size of each string. */
249
17
        GX_UTILITY_USHORT_CHECK(string_count)
250
16
        GX_UTILITY_MATH_USHORT_MULT((USHORT)string_count, sizeof(GX_CHAR *), needed_buffer_size)
251
252
        /* As string_count is an integer, the maximum needed_buffer_size is 65532,
253
           so that needed_buffer_size can not be overflow. */
254
15
        needed_buffer_size = (USHORT)(needed_buffer_size + 2);
255
256
121
        for (index = 0; index < string_count; index++)
257
        {
258
110
            if (string_list[index])
259
            {
260
109
                status = _gx_utility_string_length_check(string_list[index], &length, GX_MAX_STRING_LENGTH);
261
262
109
                if (status != GX_SUCCESS)
263
                {
264
1
                    return status;
265
                }
266
267
108
                GX_UTILITY_USHORT_CHECK(length)
268
107
                GX_UTILITY_MATH_USHORT_ADD(needed_buffer_size, (USHORT)length, needed_buffer_size)
269
106
                GX_UTILITY_MATH_USHORT_ADD(needed_buffer_size, 1, needed_buffer_size)
270
            }
271
        }
272
    }
273
    else
274
    {
275
4
        needed_buffer_size = 0;
276
    }
277
278
15
    if (needed_buffer_size)
279
    {
280
        /* check to see if we have already allocated sufficient memory */
281
11
        if (list_ptr)
282
        {
283
6
            byte = (GX_UBYTE *)list_ptr;
284
6
            current_buffer_size = *byte++;
285
6
            current_buffer_size = (USHORT)(current_buffer_size << 8);
286
6
            current_buffer_size = (USHORT)(current_buffer_size | (*byte++));
287
288
6
            if (current_buffer_size < needed_buffer_size)
289
            {
290
                /* if our buffer is not large enough, free the current buffer */
291
3
                _gx_system_memory_free((void *)list_ptr);
292
293
                /* and attempt to allocate a new buffer */
294
3
                list_ptr = (GX_CHAR **)_gx_system_memory_allocator(needed_buffer_size);
295
            }
296
        }
297
        else
298
        {
299
            /* the current buffer is NULL, attempt to allocate a new buffer */
300
5
            list_ptr = (GX_CHAR **)_gx_system_memory_allocator(needed_buffer_size);
301
        }
302
303
11
        if (list_ptr)
304
        {
305
9
            *ptr_address = (GX_CONST GX_CHAR **)list_ptr;
306
9
            byte = (GX_UBYTE *)list_ptr;
307
9
            *byte++ = (GX_UBYTE)(needed_buffer_size >> 8);
308
9
            *byte++ = (GX_UBYTE)(needed_buffer_size & 0xff);
309
310
9
            list_ptr = (GX_CHAR **)byte;
311
9
            string_ptr = (GX_CHAR *)(byte + ((INT)sizeof(GX_CHAR *)) * string_count);
312
313
88
            for (index = 0; index < string_count; index++)
314
            {
315
79
                list_ptr[index] = string_ptr;
316
317
79
                if (string_list[index])
318
                {
319
                    /* Get string length. */
320
78
                    _gx_utility_string_length_check(string_list[index], &length, GX_MAX_STRING_LENGTH);
321
322
78
                    memcpy((VOID *)string_ptr, string_list[index], length + 1); /* Use case of memcpy is verified. */
323
                }
324
                else
325
                {
326
1
                    *string_ptr = '\0';
327
1
                    length = 0;
328
                }
329
330
79
                string_ptr += length + 1;
331
            }
332
        }
333
    }
334
    else
335
    {
336
        /* here if the new text is GX_NULL, free our buffer if one has been allocated */
337
4
        if (list_ptr)
338
        {
339
1
            _gx_system_memory_free((void *)list_ptr);
340
1
            *ptr_address = GX_NULL;
341
        }
342
4
        return GX_SUCCESS;
343
    }
344
11
    if (list_ptr)
345
    {
346
9
        return(GX_SUCCESS);
347
    }
348
2
    return GX_SYSTEM_MEMORY_ERROR;
349
}
350
#endif
351
352
/**************************************************************************/
353
/*                                                                        */
354
/*  FUNCTION                                               RELEASE        */
355
/*                                                                        */
356
/*    _gx_system_private_string_list_copy_ext             PORTABLE C      */
357
/*                                                           6.1          */
358
/*  AUTHOR                                                                */
359
/*                                                                        */
360
/*    Kenneth Maxwell, Microsoft Corporation                              */
361
/*                                                                        */
362
/*  DESCRIPTION                                                           */
363
/*                                                                        */
364
/*    This service makes a private copy of string list assigned to a      */
365
/*    widget.                                                             */
366
/*                                                                        */
367
/*                                                                        */
368
/*  INPUT                                                                 */
369
/*                                                                        */
370
/*    ptr_address                           Address of widget's string    */
371
/*                                            list pointer                */
372
/*    buffer_size                           String list buffer size       */
373
/*    string_list                           Pointer to string list        */
374
/*    string_count                          Number of string in list      */
375
/*                                                                        */
376
/*  OUTPUT                                                                */
377
/*                                                                        */
378
/*    status                                Completion status             */
379
/*                                                                        */
380
/*  CALLS                                                                 */
381
/*                                                                        */
382
/*    _gx_system_memory_allocator           Allocate dynamic memory       */
383
/*    _gx_system_memory_free                Deallocate dynamic memory     */
384
/*                                                                        */
385
/*  CALLED BY                                                             */
386
/*                                                                        */
387
/*    GUIX internal code                                                  */
388
/*                                                                        */
389
/*  RELEASE HISTORY                                                       */
390
/*                                                                        */
391
/*    DATE              NAME                      DESCRIPTION             */
392
/*                                                                        */
393
/*  05-19-2020     Kenneth Maxwell          Initial Version 6.0           */
394
/*  09-30-2020     Kenneth Maxwell          Modified comment(s),          */
395
/*                                            resulting in version 6.1    */
396
/*                                                                        */
397
/**************************************************************************/
398
16
UINT _gx_system_private_string_list_copy_ext(GX_STRING **ptr_address, USHORT *buffer_size, GX_CONST GX_STRING *string_list, INT string_count)
399
{
400
USHORT            current_buffer_size;
401
USHORT            needed_buffer_size;
402
INT               index;
403
GX_STRING        *list_ptr;
404
GX_CONST GX_CHAR *string_ptr;
405
UINT              length;
406
407
16
    list_ptr = *ptr_address;
408
409
16
    if (_gx_system_memory_allocator == GX_NULL)
410
    {
411
1
        return GX_SYSTEM_MEMORY_ERROR;
412
    }
413
414
    /* are we assigning a non-NULL string array? */
415
15
    if (string_list)
416
    {
417
        /* calculate size of needed buffer. buffer size for holding each string pointer +
418
                                            buffer size of each string. */
419
13
        needed_buffer_size = (USHORT)(((INT)sizeof(GX_STRING)) * string_count);
420
93
        for (index = 0; index < string_count; index++)
421
        {
422
83
            if (string_list[index].gx_string_ptr)
423
            {
424
81
                GX_UTILITY_USHORT_CHECK(string_list[index].gx_string_length)
425
80
                GX_UTILITY_MATH_USHORT_ADD(needed_buffer_size, (USHORT)string_list[index].gx_string_length, needed_buffer_size)
426
79
                GX_UTILITY_MATH_USHORT_ADD(needed_buffer_size, 1, needed_buffer_size)
427
            }
428
        }
429
    }
430
    else
431
    {
432
2
        needed_buffer_size = 0;
433
    }
434
435
12
    if (needed_buffer_size)
436
    {
437
        /* check to see if we have already allocated sufficient memory */
438
10
        if (list_ptr)
439
        {
440
2
            current_buffer_size = *buffer_size;
441
442
2
            if (current_buffer_size < needed_buffer_size)
443
            {
444
                /* if our buffer is not large enough, free the current buffer */
445
1
                _gx_system_memory_free((void *)list_ptr);
446
447
                /* and attempt to allocate a new buffer */
448
1
                list_ptr = (GX_STRING *)_gx_system_memory_allocator(needed_buffer_size);
449
1
                *buffer_size = needed_buffer_size;
450
            }
451
        }
452
        else
453
        {
454
            /* the current buffer is NULL, attempt to allocate a new buffer */
455
8
            list_ptr = (GX_STRING *)_gx_system_memory_allocator(needed_buffer_size);
456
8
            *buffer_size = needed_buffer_size;
457
        }
458
459
10
        if (list_ptr)
460
        {
461
9
            *ptr_address = list_ptr;
462
463
9
            string_ptr = (GX_CONST GX_CHAR *)(list_ptr + string_count);
464
465
87
            for (index = 0; index < string_count; index++)
466
            {
467
78
                length = string_list[index].gx_string_length;
468
469
78
                list_ptr[index].gx_string_ptr = string_ptr;
470
78
                list_ptr[index].gx_string_length = length;
471
472
78
                if (string_list[index].gx_string_ptr)
473
                {
474
76
                    memcpy((VOID *)string_ptr, string_list[index].gx_string_ptr, length + 1); /* Use case of memcpy is verified. */
475
76
                    string_ptr += length + 1;
476
                }
477
            }
478
        }
479
    }
480
    else
481
    {
482
        /* here if the new text is GX_NULL, free our buffer if one has been allocated */
483
2
        if (list_ptr)
484
        {
485
1
            _gx_system_memory_free((void *)list_ptr);
486
1
            *ptr_address = GX_NULL;
487
1
            *buffer_size = 0;
488
        }
489
2
        return GX_SUCCESS;
490
    }
491
10
    if (list_ptr)
492
    {
493
9
        return(GX_SUCCESS);
494
    }
495
496
1
    return GX_SYSTEM_MEMORY_ERROR;
497
}
498
499
/**************************************************************************/
500
/*                                                                        */
501
/*  FUNCTION                                               RELEASE        */
502
/*                                                                        */
503
/*    _gx_system_private_string_get                       PORTABLE C      */
504
/*                                                           6.1          */
505
/*  AUTHOR                                                                */
506
/*                                                                        */
507
/*    Kenneth Maxwell, Microsoft Corporation                              */
508
/*                                                                        */
509
/*  DESCRIPTION                                                           */
510
/*                                                                        */
511
/*    This service returns the string pointer in a dynamically copied     */
512
/*    string buffer.                                                      */
513
/*                                                                        */
514
/*                                                                        */
515
/*  INPUT                                                                 */
516
/*                                                                        */
517
/*    buffer                                string buffer address         */
518
/*    style                                 calling widget style          */
519
/*                                                                        */
520
/*  OUTPUT                                                                */
521
/*                                                                        */
522
/*    None                                                                */
523
/*                                                                        */
524
/*  CALLS                                                                 */
525
/*                                                                        */
526
/*                                                                        */
527
/*  CALLED BY                                                             */
528
/*                                                                        */
529
/*    _gx_checkbox_draw                                                   */
530
/*                                                                        */
531
/*  RELEASE HISTORY                                                       */
532
/*                                                                        */
533
/*    DATE              NAME                      DESCRIPTION             */
534
/*                                                                        */
535
/*  05-19-2020     Kenneth Maxwell          Initial Version 6.0           */
536
/*  09-30-2020     Kenneth Maxwell          Modified comment(s),          */
537
/*                                            resulting in version 6.1    */
538
/*                                                                        */
539
/**************************************************************************/
540
195943
VOID _gx_system_private_string_get(GX_CONST GX_STRING *input, GX_STRING *output, ULONG style)
541
{
542
GX_UBYTE *temp;
543
544
195943
    output -> gx_string_ptr = GX_NULL;
545
195943
    output -> gx_string_length  = 0;
546
547
195943
    if (input -> gx_string_ptr == GX_NULL)
548
    {
549
569
        return;
550
    }
551
552
195374
    if (style & GX_STYLE_TEXT_COPY)
553
    {
554
        /* If the string has been dynamically copied, then the first two bytes of
555
           the string buffer hold the buffer size. Skip those bytes and return
556
           pointer to the actual string
557
         */
558
83
        temp = (GX_UBYTE *)input -> gx_string_ptr;
559
83
        temp += 2;
560
83
        output -> gx_string_ptr = (GX_CHAR *)temp;
561
83
        output -> gx_string_length = input -> gx_string_length;
562
    }
563
    else
564
    {
565
        /* No dynamic copy, the buffer is the string */
566
195291
        output -> gx_string_ptr = input -> gx_string_ptr;
567
195291
        output -> gx_string_length = input -> gx_string_length;
568
    }
569
}
570
571
/**************************************************************************/
572
/*                                                                        */
573
/*  FUNCTION                                               RELEASE        */
574
/*                                                                        */
575
/*    _gx_system_private_string_list_get                  PORTABLE C      */
576
/*                                                           6.1          */
577
/*  AUTHOR                                                                */
578
/*                                                                        */
579
/*    Kenneth Maxwell, Microsoft Corporation                              */
580
/*                                                                        */
581
/*  DESCRIPTION                                                           */
582
/*                                                                        */
583
/*    This service returns the string pointer in a dynamically copied     */
584
/*    string buffer.                                                      */
585
/*                                                                        */
586
/*                                                                        */
587
/*  INPUT                                                                 */
588
/*                                                                        */
589
/*    buffer                                string buffer address         */
590
/*    style                                 calling widget style          */
591
/*                                                                        */
592
/*  OUTPUT                                                                */
593
/*                                                                        */
594
/*    None                                                                */
595
/*                                                                        */
596
/*  CALLS                                                                 */
597
/*                                                                        */
598
/*                                                                        */
599
/*  CALLED BY                                                             */
600
/*                                                                        */
601
/*    _gx_checkbox_draw                                                   */
602
/*                                                                        */
603
/*  RELEASE HISTORY                                                       */
604
/*                                                                        */
605
/*    DATE              NAME                      DESCRIPTION             */
606
/*                                                                        */
607
/*  05-19-2020     Kenneth Maxwell          Initial Version 6.0           */
608
/*  09-30-2020     Kenneth Maxwell          Modified comment(s),          */
609
/*                                            resulting in version 6.1    */
610
/*                                                                        */
611
/**************************************************************************/
612
#if defined(GX_ENABLE_DEPRECATED_STRING_API)
613
105
VOID _gx_system_private_string_list_get(GX_CONST GX_CHAR **input, GX_CONST GX_CHAR ***output, ULONG style)
614
{
615
GX_UBYTE *temp;
616
617
105
    if (style & GX_STYLE_TEXT_COPY)
618
    {
619
        /* If the string has been dynamically copied, then the first two bytes of
620
            the string buffer hold the buffer size. Skip those bytes and return
621
            pointer to the actual string
622
         */
623
41
        temp = (GX_UBYTE *)input;
624
41
        temp += 2;
625
626
41
        *output = (GX_CONST GX_CHAR **)temp;
627
    }
628
    else
629
    {
630
64
        *output = input;
631
    }
632
105
}
633
#endif
634