1 /*
2 * Byte size string functions
3 *
4 * Copyright (C) 2010-2021, Joachim Metz <joachim.metz@gmail.com>
5 *
6 * Refer to AUTHORS for acknowledgements.
7 *
8 * This program is free software: you can redistribute it and/or modify
9 * it under the terms of the GNU Lesser General Public License as published by
10 * the Free Software Foundation, either version 3 of the License, or
11 * (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU Lesser General Public License
19 * along with this program. If not, see <https://www.gnu.org/licenses/>.
20 */
21
22 #include <common.h>
23 #include <narrow_string.h>
24 #include <system_string.h>
25 #include <types.h>
26 #include <wide_string.h>
27
28 #include "byte_size_string.h"
29 #include "qcowtools_libcerror.h"
30 #include "qcowtools_libclocale.h"
31 #include "qcowtools_libcnotify.h"
32
33 /* Creates a human readable byte size string
34 * Returns 1 if successful or -1 on error
35 */
byte_size_string_create(system_character_t * byte_size_string,size_t byte_size_string_length,uint64_t size,int units,libcerror_error_t ** error)36 int byte_size_string_create(
37 system_character_t *byte_size_string,
38 size_t byte_size_string_length,
39 uint64_t size,
40 int units,
41 libcerror_error_t **error )
42 {
43 static char *function = "byte_size_string_create";
44 int decimal_point = 0;
45
46 if( libclocale_locale_get_decimal_point(
47 &decimal_point,
48 error ) != 1 )
49 {
50 libcerror_error_set(
51 error,
52 LIBCERROR_ERROR_DOMAIN_RUNTIME,
53 LIBCERROR_RUNTIME_ERROR_GET_FAILED,
54 "%s: unable to retrieve locale decimal point.",
55 function );
56
57 return( -1 );
58 }
59 if( byte_size_string_create_with_decimal_point(
60 byte_size_string,
61 byte_size_string_length,
62 size,
63 units,
64 decimal_point,
65 error ) != 1 )
66 {
67 libcerror_error_set(
68 error,
69 LIBCERROR_ERROR_DOMAIN_RUNTIME,
70 LIBCERROR_RUNTIME_ERROR_SET_FAILED,
71 "%s: unable to create byte size string.",
72 function );
73
74 return( -1 );
75 }
76 return( 1 );
77 }
78
79 /* Creates a human readable byte size string
80 * Returns 1 if successful or -1 on error
81 */
byte_size_string_create_with_decimal_point(system_character_t * byte_size_string,size_t byte_size_string_length,uint64_t size,int units,int decimal_point,libcerror_error_t ** error)82 int byte_size_string_create_with_decimal_point(
83 system_character_t *byte_size_string,
84 size_t byte_size_string_length,
85 uint64_t size,
86 int units,
87 int decimal_point,
88 libcerror_error_t **error )
89 {
90 const system_character_t *factor_string = NULL;
91 const system_character_t *units_string = NULL;
92 static char *function = "byte_size_string_create_with_decimal_point";
93 ssize_t print_count = 0;
94 uint64_t factored_size = 0;
95 uint64_t last_factored_size = 0;
96 int8_t factor = 0;
97 int8_t remainder = -1;
98
99 if( byte_size_string == NULL )
100 {
101 libcerror_error_set(
102 error,
103 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
104 LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
105 "%s: invalid byte size string.",
106 function );
107
108 return( -1 );
109 }
110 /* Minimum of 4 digits and separator, space, 3 letter unit, end of string
111 */
112 if( byte_size_string_length < 9 )
113 {
114 libcerror_error_set(
115 error,
116 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
117 LIBCERROR_ARGUMENT_ERROR_VALUE_TOO_SMALL,
118 "%s: byte size string too small.",
119 function );
120
121 return( -1 );
122 }
123 if( ( size < 1024 )
124 || ( units == BYTE_SIZE_STRING_UNIT_MEGABYTE ) )
125 {
126 units_string = _SYSTEM_STRING( "B" );
127 }
128 else if( units == BYTE_SIZE_STRING_UNIT_MEBIBYTE )
129 {
130 units_string = _SYSTEM_STRING( "iB" );
131 }
132 factored_size = size;
133
134 if( factored_size >= (uint64_t) units )
135 {
136 while( factored_size >= (uint64_t) units )
137 {
138 last_factored_size = factored_size;
139 factored_size /= units;
140
141 factor++;
142 }
143 if( factored_size < 10 )
144 {
145 last_factored_size %= units;
146 remainder = (int8_t) ( last_factored_size / 100 );
147 }
148 }
149 switch( factor )
150 {
151 case 0:
152 factor_string = _SYSTEM_STRING( "" );
153 break;
154
155 case 1:
156 factor_string = _SYSTEM_STRING( "K" );
157 break;
158
159 case 2:
160 factor_string = _SYSTEM_STRING( "M" );
161 break;
162
163 case 3:
164 factor_string = _SYSTEM_STRING( "G" );
165 break;
166
167 case 4:
168 factor_string = _SYSTEM_STRING( "T" );
169 break;
170
171 case 5:
172 factor_string = _SYSTEM_STRING( "P" );
173 break;
174
175 case 6:
176 factor_string = _SYSTEM_STRING( "E" );
177 break;
178
179 case 7:
180 factor_string = _SYSTEM_STRING( "Z" );
181 break;
182
183 case 8:
184 factor_string = _SYSTEM_STRING( "Y" );
185 break;
186
187 default:
188 libcerror_error_set(
189 error,
190 LIBCERROR_ERROR_DOMAIN_RUNTIME,
191 LIBCERROR_RUNTIME_ERROR_UNSUPPORTED_VALUE,
192 "%s: unsupported size factor.",
193 function );
194
195 return( -1 );
196 }
197 if( remainder > 9 )
198 {
199 remainder = 9;
200 }
201 if( remainder >= 0 )
202 {
203 print_count = system_string_sprintf(
204 byte_size_string,
205 byte_size_string_length,
206 _SYSTEM_STRING( "%" ) _SYSTEM_STRING( PRIu64 )
207 _SYSTEM_STRING( "%" ) _SYSTEM_STRING( PRIc_SYSTEM )
208 _SYSTEM_STRING( "%" ) _SYSTEM_STRING( PRIu8 )
209 _SYSTEM_STRING( " %" ) _SYSTEM_STRING( PRIs_SYSTEM )
210 _SYSTEM_STRING( "%" ) _SYSTEM_STRING( PRIs_SYSTEM ),
211 factored_size,
212 (system_character_t) decimal_point,
213 remainder,
214 factor_string,
215 units_string );
216 }
217 else
218 {
219 print_count = system_string_sprintf(
220 byte_size_string,
221 byte_size_string_length,
222 _SYSTEM_STRING( "%" ) _SYSTEM_STRING( PRIu64 )
223 _SYSTEM_STRING( " %" ) _SYSTEM_STRING( PRIs_SYSTEM )
224 _SYSTEM_STRING( "%" ) _SYSTEM_STRING( PRIs_SYSTEM ),
225 factored_size,
226 factor_string,
227 units_string );
228 }
229 if( ( print_count < 0 )
230 || ( (size_t) print_count > byte_size_string_length ) )
231 {
232 libcerror_error_set(
233 error,
234 LIBCERROR_ERROR_DOMAIN_RUNTIME,
235 LIBCERROR_RUNTIME_ERROR_SET_FAILED,
236 "%s: unable to set byte size string.",
237 function );
238
239 return( -1 );
240 }
241 return( 1 );
242 }
243
244 /* Converts a human readable byte size string into a value
245 * Returns 1 if successful or -1 on error
246 */
byte_size_string_convert(const system_character_t * byte_size_string,size_t byte_size_string_length,uint64_t * size,libcerror_error_t ** error)247 int byte_size_string_convert(
248 const system_character_t *byte_size_string,
249 size_t byte_size_string_length,
250 uint64_t *size,
251 libcerror_error_t **error )
252 {
253 static char *function = "byte_size_string_convert";
254 int decimal_point = 0;
255
256 if( libclocale_locale_get_decimal_point(
257 &decimal_point,
258 error ) != 1 )
259 {
260 libcerror_error_set(
261 error,
262 LIBCERROR_ERROR_DOMAIN_RUNTIME,
263 LIBCERROR_RUNTIME_ERROR_GET_FAILED,
264 "%s: unable to retrieve locale decimal point.",
265 function );
266
267 return( -1 );
268 }
269 if( byte_size_string_convert_with_decimal_point(
270 byte_size_string,
271 byte_size_string_length,
272 decimal_point,
273 size,
274 error ) != 1 )
275 {
276 libcerror_error_set(
277 error,
278 LIBCERROR_ERROR_DOMAIN_RUNTIME,
279 LIBCERROR_RUNTIME_ERROR_GET_FAILED,
280 "%s: unable to retrieve byte size from string.",
281 function );
282
283 return( -1 );
284 }
285 return( 1 );
286 }
287
288 /* Converts a human readable byte size string into a value
289 * Returns 1 if successful or -1 on error
290 */
byte_size_string_convert_with_decimal_point(const system_character_t * byte_size_string,size_t byte_size_string_length,int decimal_point,uint64_t * size,libcerror_error_t ** error)291 int byte_size_string_convert_with_decimal_point(
292 const system_character_t *byte_size_string,
293 size_t byte_size_string_length,
294 int decimal_point,
295 uint64_t *size,
296 libcerror_error_t **error )
297 {
298 static char *function = "byte_size_string_convert_with_decimal_point";
299 size_t byte_size_string_iterator = 0;
300 uint64_t byte_size = 0;
301 int8_t factor = 0;
302 int8_t remainder = -1;
303 int units = 0;
304
305 if( byte_size_string == NULL )
306 {
307 libcerror_error_set(
308 error,
309 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
310 LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
311 "%s: invalid byte size string.",
312 function );
313
314 return( -1 );
315 }
316 if( size == NULL )
317 {
318 libcerror_error_set(
319 error,
320 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
321 LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
322 "%s: invalid size.",
323 function );
324
325 return( -1 );
326 }
327 while( byte_size_string_iterator < byte_size_string_length )
328 {
329 if( ( byte_size_string[ byte_size_string_iterator ] < (system_character_t) '0' )
330 || ( byte_size_string[ byte_size_string_iterator ] > (system_character_t) '9' ) )
331 {
332 break;
333 }
334 byte_size *= 10;
335 byte_size += ( byte_size_string[ byte_size_string_iterator ] - (system_character_t) '0' );
336
337 byte_size_string_iterator++;
338 }
339 if( byte_size_string[ byte_size_string_iterator ] == (system_character_t) decimal_point )
340 {
341 byte_size_string_iterator++;
342
343 if( ( byte_size_string[ byte_size_string_iterator ] >= (system_character_t) '0' )
344 && ( byte_size_string[ byte_size_string_iterator ] <= (system_character_t) '9' ) )
345 {
346 remainder = (int8_t) ( byte_size_string[ byte_size_string_iterator ] - (system_character_t) '0' );
347
348 byte_size_string_iterator++;
349 }
350 remainder *= 10;
351
352 if( ( byte_size_string[ byte_size_string_iterator ] >= (system_character_t) '0' )
353 && ( byte_size_string[ byte_size_string_iterator ] <= (system_character_t) '9' ) )
354 {
355 remainder += (int8_t) ( byte_size_string[ byte_size_string_iterator ] - (system_character_t) '0' );
356
357 byte_size_string_iterator++;
358 }
359 /* Ignore more than 2 digits after separator
360 */
361 while( byte_size_string_iterator < byte_size_string_length )
362 {
363 if( ( byte_size_string[ byte_size_string_iterator ] < (system_character_t) '0' )
364 || ( byte_size_string[ byte_size_string_iterator ] > (system_character_t) '9' ) )
365 {
366 break;
367 }
368 byte_size_string_iterator++;
369 }
370 }
371 if( byte_size_string[ byte_size_string_iterator ] == (system_character_t) ' ' )
372 {
373 byte_size_string_iterator++;
374 }
375 switch( byte_size_string[ byte_size_string_iterator ] )
376 {
377 case 'k':
378 case 'K':
379 factor = 1;
380 break;
381
382 case 'm':
383 case 'M':
384 factor = 2;
385 break;
386
387 case 'g':
388 case 'G':
389 factor = 3;
390 break;
391
392 case 't':
393 case 'T':
394 factor = 4;
395 break;
396
397 case 'p':
398 case 'P':
399 factor = 5;
400 break;
401
402 case 'e':
403 case 'E':
404 factor = 6;
405 break;
406
407 case 'z':
408 case 'Z':
409 factor = 7;
410 break;
411
412 case 'y':
413 case 'Y':
414 factor = 8;
415 break;
416
417 default:
418 break;
419 }
420 if( factor >= 1 )
421 {
422 byte_size_string_iterator++;
423 }
424 if( byte_size_string_iterator >= byte_size_string_length )
425 {
426 units = BYTE_SIZE_STRING_UNIT_MEBIBYTE;
427 }
428 else if( ( byte_size_string[ byte_size_string_iterator ] == (system_character_t) 'i' )
429 && ( byte_size_string[ byte_size_string_iterator + 1 ] == (system_character_t) 'B' ) )
430 {
431 units = BYTE_SIZE_STRING_UNIT_MEBIBYTE;
432
433 byte_size_string_iterator += 2;
434 }
435 else if( byte_size_string[ byte_size_string_iterator ] == (system_character_t) 'B' )
436 {
437 units = BYTE_SIZE_STRING_UNIT_MEGABYTE;
438
439 byte_size_string_iterator++;
440 }
441 else
442 {
443 libcerror_error_set(
444 error,
445 LIBCERROR_ERROR_DOMAIN_RUNTIME,
446 LIBCERROR_RUNTIME_ERROR_VALUE_OUT_OF_BOUNDS,
447 "%s: invalid units.",
448 function );
449
450 return( -1 );
451 }
452 if( factor > 0 )
453 {
454 if( remainder > 0 )
455 {
456 byte_size *= units;
457
458 factor--;
459
460 byte_size += ( remainder * 10 );
461 }
462 for( ; factor > 0; factor-- )
463 {
464 byte_size *= units;
465 }
466 }
467 #if defined( HAVE_VERBOSE_OUTPUT )
468 else if( remainder >= 0 )
469 {
470 libcnotify_printf(
471 "%s: ignoring byte value remainder.\n",
472 function );
473 }
474 #endif
475 #if defined( HAVE_VERBOSE_OUTPUT )
476 if( ( byte_size_string[ byte_size_string_iterator ] != 0 )
477 && ( byte_size_string[ byte_size_string_iterator ] != (system_character_t) ' ' )
478 && ( byte_size_string[ byte_size_string_iterator ] != (system_character_t) '\n' )
479 && ( byte_size_string[ byte_size_string_iterator ] != (system_character_t) '\r' ) )
480 {
481 libcnotify_printf(
482 "%s: trailing data in byte size string.\n",
483 function );
484 }
485 #endif
486 *size = byte_size;
487
488 return( 1 );
489 }
490
491