1 /* 2 * Copyright (C) 2014 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 #include <ctype.h> 18 #include "dmStringUtil.h" 19 #include "dmNewDataTypesValidation.h" 20 #include "xpl_Logger.h" 21 22 //---------------------------------------------------------------------------------------------- 23 24 typedef int position_t; 25 typedef int offset_t; 26 27 //---------------------------------------------------------------------------------------------- 28 29 class matcher_t 30 { 31 public: 32 matcher_t( const DMString& str ); 33 matcher_t( const matcher_t& matcher ); 34 BOOLEAN get_char( char& curr_char, offset_t offset ) const; 35 BOOLEAN advance( offset_t offset ); 36 offset_t get_offset() const; 37 position_t get_size() const; 38 39 private: 40 position_t _position; 41 position_t _initial_position; 42 const DMString& _str; 43 }; 44 45 typedef offset_t (*check_format_fn_t)( matcher_t matcher ); 46 47 //---------------------------------------------------------------------------------------------- 48 49 matcher_t::matcher_t( const DMString& str ) 50 : _position( 0 ), 51 _initial_position( 0 ), 52 _str( str ) 53 { 54 } 55 56 matcher_t::matcher_t( const matcher_t& matcher ) 57 : _position( matcher._position ), 58 _initial_position( matcher._position ), 59 _str( matcher._str ) 60 { 61 } 62 63 BOOLEAN 64 matcher_t::advance( offset_t offset ) 65 { 66 BOOLEAN result = FALSE; 67 68 if( ( offset > 0 ) && 69 ( _position + offset <= get_size() ) ) 70 { 71 _position += offset; 72 result = TRUE; 73 } 74 75 return result; 76 } 77 78 BOOLEAN 79 matcher_t::get_char( char& curr_char, offset_t offset ) const 80 { 81 BOOLEAN result = FALSE; 82 83 if( _position + offset < get_size() ) 84 { 85 curr_char = _str[ _position + offset ]; 86 result = TRUE; 87 } 88 89 return result; 90 } 91 92 offset_t 93 matcher_t::get_offset() const 94 { 95 return _position - _initial_position; 96 } 97 98 position_t 99 matcher_t::get_size() const 100 { 101 return static_cast<position_t>( _str.length() ); 102 } 103 104 //---------------------------------------------------------------------------------------------- 105 106 static 107 offset_t 108 is_literal( matcher_t matcher, char literal ) 109 { 110 char curr_char = '\0'; 111 return ( matcher.get_char( curr_char, 0 ) && ( curr_char == literal ) ) ? 1 : 0; 112 } 113 114 static 115 offset_t 116 is_sign( matcher_t matcher ) 117 { 118 offset_t offset = is_literal( matcher, '-' ); 119 120 if( !offset ) 121 { 122 offset = is_literal( matcher, '+' ); 123 } 124 125 return offset; 126 } 127 128 static 129 offset_t 130 is_digit( matcher_t matcher ) 131 { 132 char curr_char = '\0'; 133 return ( matcher.get_char( curr_char, 0 ) && isdigit( curr_char ) ) ? 1 : 0; 134 } 135 136 static 137 offset_t 138 is_number( matcher_t matcher, int min_length, int max_length ) 139 { 140 for( int i = 0; i < min_length; ++i ) 141 { 142 if( !matcher.advance( is_digit( matcher ) ) ) 143 { 144 return 0; 145 } 146 } 147 148 for( int i = min_length; i < max_length; ++i ) 149 { 150 if( !matcher.advance( is_digit( matcher ) ) ) 151 { 152 return matcher.get_offset(); 153 } 154 } 155 156 return matcher.get_offset(); 157 } 158 159 static 160 offset_t 161 is_integer_part( matcher_t matcher ) 162 { 163 return is_number( matcher, 1, 10 ); 164 } 165 166 static 167 offset_t 168 is_fractional_part( matcher_t matcher ) 169 { 170 if( !matcher.advance( is_literal( matcher, '.' ) ) ) return 0; 171 if( !matcher.advance( is_number( matcher, 1, 10 ) ) ) return 0; 172 173 return matcher.get_offset(); 174 } 175 176 static 177 offset_t 178 is_Ee( matcher_t matcher ) 179 { 180 offset_t offset = is_literal( matcher, 'E' ); 181 182 if( !offset ) 183 { 184 offset = is_literal( matcher, 'e' ); 185 } 186 187 return offset; 188 } 189 190 static 191 offset_t 192 is_exponent( matcher_t matcher ) 193 { 194 if( !matcher.advance( is_Ee( matcher ) ) ) return 0; 195 196 matcher.advance( is_sign( matcher ) ); 197 if( !matcher.advance( is_number( matcher, 1, 10 ) ) ) return 0; 198 199 return matcher.get_offset(); 200 } 201 202 static 203 offset_t 204 is_mantissa( matcher_t matcher ) 205 { 206 matcher.advance( is_sign( matcher ) ); 207 208 if( !matcher.advance( is_integer_part( matcher ) ) ) return 0; 209 210 matcher.advance( is_fractional_part( matcher ) ); 211 212 return matcher.get_offset(); 213 } 214 215 BOOLEAN 216 is_float( const DMString& str ) 217 { 218 XPL_LOG_DM_TMN_Debug(("dmNewDataTypesValidation::is_float str=%s\n", str.c_str())); 219 matcher_t matcher( str ); 220 221 if( matcher.get_size() == 0 ) return FALSE; 222 if( !matcher.advance( is_mantissa( matcher ) ) ) return FALSE; 223 matcher.advance( is_exponent( matcher ) ); 224 225 return matcher.get_offset() == str.length(); 226 } 227 228 static 229 offset_t 230 is_year( matcher_t matcher ) 231 { 232 return is_number( matcher, 4, 4 ); 233 } 234 235 static 236 offset_t 237 is_number_in_range( matcher_t matcher, int num_digits, int min_value, int max_value ) 238 { 239 offset_t offset = is_number( matcher, num_digits, num_digits ); 240 241 if( offset == 0 ) return 0; 242 243 int value = 0; 244 245 for( int i = 0; i < num_digits; ++i ) 246 { 247 char curr_char = '\0'; 248 249 if( !matcher.get_char( curr_char, i ) ) return 0; 250 251 value = 10 * value + ( curr_char - '0' ); 252 } 253 254 return ( min_value <= value ) && ( value <= max_value ) ? offset : 0; 255 } 256 257 static 258 offset_t 259 is_month( matcher_t matcher ) 260 { 261 return is_number_in_range( matcher, 2, 1, 12 ); 262 } 263 264 static 265 offset_t 266 is_day_of_month( matcher_t matcher ) 267 { 268 return is_number_in_range( matcher, 2, 1, 31 ); 269 } 270 271 static 272 offset_t 273 is_day_of_year( matcher_t matcher ) 274 { 275 return is_number_in_range( matcher, 3, 1, 366 ); 276 } 277 278 static 279 offset_t 280 is_day_of_week( matcher_t matcher ) 281 { 282 return is_number_in_range( matcher, 1, 1, 7 ); 283 } 284 285 static 286 offset_t 287 is_week_number( matcher_t matcher ) 288 { 289 return is_number_in_range( matcher, 2, 1, 52 ); 290 } 291 292 static 293 offset_t 294 is_YYYY( matcher_t matcher ) 295 { 296 if( !matcher.advance( is_year( matcher ) ) ) return 0; 297 298 return matcher.get_offset(); 299 } 300 301 static 302 offset_t 303 is_YYYY_MM_DD( matcher_t matcher ) 304 { 305 if( !matcher.advance( is_year( matcher ) ) ) return 0; 306 if( !matcher.advance( is_literal( matcher, '-' ) ) ) return 0; 307 if( !matcher.advance( is_month( matcher ) ) ) return 0; 308 if( !matcher.advance( is_literal( matcher, '-' ) ) ) return 0; 309 if( !matcher.advance( is_day_of_month( matcher ) ) ) return 0; 310 311 return matcher.get_offset(); 312 } 313 314 static 315 offset_t 316 is_YYYY_MM( matcher_t matcher ) 317 { 318 if( !matcher.advance( is_year( matcher ) ) ) return 0; 319 if( !matcher.advance( is_literal( matcher, '-' ) ) ) return 0; 320 if( !matcher.advance( is_month( matcher ) ) ) return 0; 321 322 return matcher.get_offset(); 323 } 324 325 static 326 offset_t 327 is_YYYY_DDD( matcher_t matcher ) 328 { 329 if( !matcher.advance( is_year( matcher ) ) ) return 0; 330 if( !matcher.advance( is_literal( matcher, '-' ) ) ) return 0; 331 if( !matcher.advance( is_day_of_year( matcher ) ) ) return 0; 332 333 return matcher.get_offset(); 334 } 335 336 static 337 offset_t 338 is_YYYY_Wxx( matcher_t matcher ) 339 { 340 if( !matcher.advance( is_year( matcher ) ) ) return 0; 341 if( !matcher.advance( is_literal( matcher, '-' ) ) ) return 0; 342 if( !matcher.advance( is_literal( matcher, 'W' ) ) ) return 0; 343 if( !matcher.advance( is_week_number( matcher ) ) ) return 0; 344 345 return matcher.get_offset(); 346 } 347 348 static 349 offset_t 350 is_YYYY_Wxx_d( matcher_t matcher ) 351 { 352 if( !matcher.advance( is_year( matcher ) ) ) return 0; 353 if( !matcher.advance( is_literal( matcher, '-' ) ) ) return 0; 354 if( !matcher.advance( is_literal( matcher, 'W' ) ) ) return 0; 355 if( !matcher.advance( is_week_number( matcher ) ) ) return 0; 356 if( !matcher.advance( is_literal( matcher, '-' ) ) ) return 0; 357 if( !matcher.advance( is_day_of_week( matcher ) ) ) return 0; 358 359 return matcher.get_offset(); 360 } 361 362 static 363 offset_t 364 is_YYYYMMDD( matcher_t matcher ) 365 { 366 if( !matcher.advance( is_year( matcher ) ) ) return 0; 367 if( !matcher.advance( is_month( matcher ) ) ) return 0; 368 if( !matcher.advance( is_day_of_month( matcher ) ) ) return 0; 369 370 return matcher.get_offset(); 371 } 372 373 static 374 offset_t 375 is_YYYYMM( matcher_t matcher ) 376 { 377 if( !matcher.advance( is_year( matcher ) ) ) return 0; 378 if( !matcher.advance( is_month( matcher ) ) ) return 0; 379 380 return matcher.get_offset(); 381 } 382 383 static 384 offset_t 385 is_YYYYDDD( matcher_t matcher ) 386 { 387 if( !matcher.advance( is_year( matcher ) ) ) return 0; 388 if( !matcher.advance( is_day_of_year( matcher ) ) ) return 0; 389 390 return matcher.get_offset(); 391 } 392 393 static 394 offset_t 395 is_YYYYWxx( matcher_t matcher ) 396 { 397 if( !matcher.advance( is_year( matcher ) ) ) return 0; 398 if( !matcher.advance( is_literal( matcher, 'W' ) ) ) return 0; 399 if( !matcher.advance( is_week_number( matcher ) ) ) return 0; 400 401 return matcher.get_offset(); 402 } 403 404 static 405 offset_t 406 is_YYYYWxxd( matcher_t matcher ) 407 { 408 if( !matcher.advance( is_year( matcher ) ) ) return 0; 409 if( !matcher.advance( is_literal( matcher, 'W' ) ) ) return 0; 410 if( !matcher.advance( is_week_number( matcher ) ) ) return 0; 411 if( !matcher.advance( is_day_of_week( matcher ) ) ) return 0; 412 413 return matcher.get_offset(); 414 } 415 416 static 417 BOOLEAN 418 is_format( matcher_t matcher, check_format_fn_t fn ) 419 { 420 return (*fn)( matcher ) == matcher.get_size(); 421 } 422 423 BOOLEAN 424 is_date( const DMString& str ) 425 { 426 matcher_t matcher( str ); 427 BOOLEAN result = TRUE; 428 429 if( matcher.get_size() == 0 ) return FALSE; 430 431 for( ; ; ) 432 { 433 if( is_format( matcher, is_YYYY ) ) break; 434 if( is_format( matcher, is_YYYY_MM_DD ) ) break; 435 if( is_format( matcher, is_YYYY_MM ) ) break; 436 if( is_format( matcher, is_YYYY_DDD ) ) break; 437 if( is_format( matcher, is_YYYY_Wxx ) ) break; 438 if( is_format( matcher, is_YYYY_Wxx_d ) ) break; 439 if( is_format( matcher, is_YYYYMMDD ) ) break; 440 if( is_format( matcher, is_YYYYMM ) ) break; 441 if( is_format( matcher, is_YYYYDDD ) ) break; 442 if( is_format( matcher, is_YYYYWxx ) ) break; 443 if( is_format( matcher, is_YYYYWxxd ) ) break; 444 445 result = FALSE; 446 break; 447 } 448 449 return result; 450 } 451 452 static 453 offset_t 454 is_hours( matcher_t matcher ) 455 { 456 return is_number_in_range( matcher, 2, 0, 23 ); 457 } 458 459 static 460 offset_t 461 is_minutes( matcher_t matcher ) 462 { 463 return is_number_in_range( matcher, 2, 0, 59 ); 464 } 465 466 static 467 offset_t 468 is_seconds( matcher_t matcher ) 469 { 470 return is_number_in_range( matcher, 2, 0, 59 ); 471 } 472 473 static 474 offset_t 475 is_hh_mm_ss( matcher_t matcher ) 476 { 477 if( !matcher.advance( is_hours( matcher ) ) ) return 0; 478 if( !matcher.advance( is_literal( matcher, ':' ) ) ) return 0; 479 if( !matcher.advance( is_minutes( matcher ) ) ) return 0; 480 if( !matcher.advance( is_literal( matcher, ':' ) ) ) return 0; 481 if( !matcher.advance( is_seconds( matcher ) ) ) return 0; 482 483 return matcher.get_offset(); 484 } 485 486 static 487 offset_t 488 is_hh_mm( matcher_t matcher ) 489 { 490 if( !matcher.advance( is_hours( matcher ) ) ) return 0; 491 if( !matcher.advance( is_literal( matcher, ':' ) ) ) return 0; 492 if( !matcher.advance( is_minutes( matcher ) ) ) return 0; 493 494 return matcher.get_offset(); 495 } 496 497 static 498 offset_t 499 is_hhmmss( matcher_t matcher ) 500 { 501 if( !matcher.advance( is_hours( matcher ) ) ) return 0; 502 if( !matcher.advance( is_minutes( matcher ) ) ) return 0; 503 if( !matcher.advance( is_seconds( matcher ) ) ) return 0; 504 505 return matcher.get_offset(); 506 } 507 508 static 509 offset_t 510 is_hhmm( matcher_t matcher ) 511 { 512 if( !matcher.advance( is_hours( matcher ) ) ) return 0; 513 if( !matcher.advance( is_minutes( matcher ) ) ) return 0; 514 515 return matcher.get_offset(); 516 } 517 518 static 519 offset_t 520 is_hh( matcher_t matcher ) 521 { 522 if( !matcher.advance( is_hours( matcher ) ) ) return 0; 523 524 return matcher.get_offset(); 525 } 526 527 static 528 offset_t 529 is_hh_mm_ssZ( matcher_t matcher ) 530 { 531 if( !matcher.advance( is_hours( matcher ) ) ) return 0; 532 if( !matcher.advance( is_literal( matcher, ':' ) ) ) return 0; 533 if( !matcher.advance( is_minutes( matcher ) ) ) return 0; 534 if( !matcher.advance( is_literal( matcher, ':' ) ) ) return 0; 535 if( !matcher.advance( is_seconds( matcher ) ) ) return 0; 536 if( !matcher.advance( is_literal( matcher, 'Z' ) ) ) return 0; 537 538 return matcher.get_offset(); 539 } 540 541 static 542 offset_t 543 is_hh_mm_ss_utc_hh_mm( matcher_t matcher ) 544 { 545 if( !matcher.advance( is_hours( matcher ) ) ) return 0; 546 if( !matcher.advance( is_literal( matcher, ':' ) ) ) return 0; 547 if( !matcher.advance( is_minutes( matcher ) ) ) return 0; 548 if( !matcher.advance( is_literal( matcher, ':' ) ) ) return 0; 549 if( !matcher.advance( is_seconds( matcher ) ) ) return 0; 550 if( !matcher.advance( is_sign( matcher ) ) ) return 0; 551 if( !matcher.advance( is_hours( matcher ) ) ) return 0; 552 if( !matcher.advance( is_literal( matcher, ':' ) ) ) return 0; 553 if( !matcher.advance( is_minutes( matcher ) ) ) return 0; 554 555 return matcher.get_offset(); 556 } 557 558 BOOLEAN 559 is_time( const DMString& str ) 560 { 561 matcher_t matcher( str ); 562 BOOLEAN result = TRUE; 563 564 if( matcher.get_size() == 0 ) return FALSE; 565 566 for( ; ; ) 567 { 568 if( is_format( matcher, is_hh_mm_ss ) ) break; 569 if( is_format( matcher, is_hh_mm ) ) break; 570 if( is_format( matcher, is_hhmmss ) ) break; 571 if( is_format( matcher, is_hhmm ) ) break; 572 if( is_format( matcher, is_hh ) ) break; 573 if( is_format( matcher, is_hh_mm_ssZ ) ) break; 574 if( is_format( matcher, is_hh_mm_ss_utc_hh_mm ) ) break; 575 576 result = FALSE; 577 break; 578 } 579 580 return result; 581 } 582 583 /* DM: Unit tests for is_time, is_data, is_float 584 585 586 struct test_t 587 { 588 test_t( const char* pattern, BOOLEAN expeted_result ) 589 : _pattern( pattern ), 590 _expected_result( expeted_result ) 591 { 592 } 593 594 const char* _pattern; 595 BOOLEAN _expected_result; 596 }; 597 598 void test_float() 599 { 600 test_t tests[] = 601 { 602 test_t( "1", TRUE ), 603 test_t( "123", TRUE ), 604 test_t( "+523", TRUE ), 605 test_t( "-66544", TRUE ), 606 test_t( "6.0", TRUE ), 607 test_t( "-64.55", TRUE ), 608 test_t( "+66.544", TRUE ), 609 test_t( "1e12", TRUE ), 610 test_t( "123e12", TRUE ), 611 test_t( "+523e-12", TRUE ), 612 test_t( "-66544e1", TRUE ), 613 test_t( "6.0E+01", TRUE ), 614 test_t( "-64.55E12", TRUE ), 615 test_t( "+66.544e-44", TRUE ), 616 617 test_t( "", FALSE ), 618 test_t( "+66.544e-", FALSE ), 619 test_t( "-66.544e", FALSE ), 620 test_t( "+66.", FALSE ), 621 test_t( "+x6.5", FALSE ), 622 test_t( "++6.0E+01", FALSE ), 623 test_t( "--6.0E+01", FALSE ), 624 test_t( "--6.0E+-01", FALSE ), 625 test_t( "633.45.40E+01", FALSE ), 626 test_t( "633.40E+2.1", FALSE ), 627 }; 628 629 for( int i = 0; i < sizeof( tests ) / sizeof( tests[ 0 ] ); ++i ) 630 { 631 std::cout << ( ( is_float( tests[ i ]._pattern ) == tests[ i ]._expected_result ) 632 ? "OK " 633 : "Failed" ); 634 std::cout << " - float( " << tests[ i ]._pattern << " )"; 635 std::cout << std::endl; 636 } 637 } 638 639 void test_date() 640 { 641 test_t tests[] = 642 { 643 test_t( "2005-11-23", TRUE ), 644 test_t( "1243-04", TRUE ), 645 test_t( "1990-123", TRUE ), 646 test_t( "1322-W12-3", TRUE ), 647 test_t( "1600-W05", TRUE ), 648 test_t( "19121103", TRUE ), 649 test_t( "200001", TRUE ), 650 test_t( "2001222", TRUE ), 651 test_t( "000001", TRUE ), 652 test_t( "0000001", TRUE ), 653 test_t( "1555", TRUE ), 654 test_t( "2210W116", TRUE ), 655 test_t( "1203W12", TRUE ), 656 657 test_t( "20Z5-11-23", FALSE ), 658 test_t( "205-11-23", FALSE ), 659 test_t( "2025-11-2", FALSE ), 660 test_t( "2025-11-", FALSE ), 661 test_t( "2025-1-12", FALSE ), 662 test_t( "2025--12", FALSE ), 663 test_t( "2025-00-12", FALSE ), 664 test_t( "2025-44-12", FALSE ), 665 test_t( "2025-11-00", FALSE ), 666 test_t( "2025-11-65", FALSE ), 667 test_t( "1990-0", FALSE ), 668 test_t( "1990-000", FALSE ), 669 test_t( "1990-367", FALSE ), 670 test_t( "990-367", FALSE ), 671 test_t( "123-04", FALSE ), 672 test_t( "1322-W12-0", FALSE ), 673 test_t( "1322-W12-8", FALSE ), 674 test_t( "1322-W00-3", FALSE ), 675 test_t( "1322-W0-3", FALSE ), 676 test_t( "1322-W-3", FALSE ), 677 test_t( "1322-W66-3", FALSE ), 678 test_t( "155", FALSE ), 679 test_t( "1", FALSE ), 680 test_t( "", FALSE ), 681 test_t( "15522", FALSE ), 682 test_t( "1552q", FALSE ), 683 test_t( "1552-", FALSE ), 684 test_t( "1552-W", FALSE ), 685 test_t( "1552W", FALSE ), 686 test_t( "2210W1163", FALSE ), 687 test_t( "1203w12", FALSE ), 688 }; 689 690 for( int i = 0; i < sizeof( tests ) / sizeof( tests[ 0 ] ); ++i ) 691 { 692 std::cout << ( ( is_date( tests[ i ]._pattern ) == tests[ i ]._expected_result ) 693 ? "OK " 694 : "Failed" ); 695 std::cout << " - date( " << tests[ i ]._pattern << " )"; 696 std::cout << std::endl; 697 } 698 } 699 700 void test_time() 701 { 702 test_t tests[] = 703 { 704 test_t( "12:11:23", TRUE ), 705 test_t( "12:11", TRUE ), 706 test_t( "121123", TRUE ), 707 test_t( "1211", TRUE ), 708 test_t( "12", TRUE ), 709 test_t( "12:11:23Z", TRUE ), 710 test_t( "12:11:23+08:00", TRUE ), 711 test_t( "12:11:23-11:30", TRUE ), 712 713 test_t( "", FALSE ), 714 test_t( "1", FALSE ), 715 test_t( "Z", FALSE ), 716 test_t( "+1", FALSE ), 717 test_t( "25:11:23", FALSE ), 718 test_t( "15:81:23", FALSE ), 719 test_t( "15:11:73", FALSE ), 720 test_t( "::", FALSE ), 721 test_t( "1:2:3", FALSE ), 722 test_t( "12112", FALSE ), 723 test_t( "121", FALSE ), 724 test_t( "12:11:23+33:00", FALSE ), 725 test_t( "12:11:23-08:99", FALSE ), 726 test_t( "12:11:23 08:12", FALSE ), 727 test_t( "12:11:23 08:12", FALSE ), 728 test_t( "12:11:23-08:", FALSE ), 729 test_t( "12:11:23-08:1", FALSE ), 730 test_t( "12:11:23:08:11", FALSE ), 731 }; 732 733 for( int i = 0; i < sizeof( tests ) / sizeof( tests[ 0 ] ); ++i ) 734 { 735 std::cout << ( ( is_time( tests[ i ]._pattern ) == tests[ i ]._expected_result ) 736 ? "OK " 737 : "Failed" ); 738 std::cout << " - time( " << tests[ i ]._pattern << " )"; 739 std::cout << std::endl; 740 } 741 } 742 743 int main(int argc, char* argv[]) 744 { 745 test_float(); 746 test_date(); 747 test_time(); 748 749 return 0; 750 } 751 */ 752