1 31 package org.pdfbox.afmparser; 32 33 import java.io.InputStream ; 34 import java.io.IOException ; 35 36 import java.util.StringTokenizer ; 37 38 import org.pdfbox.afmtypes.Composite; 39 import org.pdfbox.afmtypes.CompositePart; 40 import org.pdfbox.afmtypes.CharMetric; 41 import org.pdfbox.afmtypes.FontMetric; 42 import org.pdfbox.afmtypes.KernPair; 43 import org.pdfbox.afmtypes.Ligature; 44 import org.pdfbox.afmtypes.TrackKern; 45 46 import org.pdfbox.util.BoundingBox; 47 48 56 public class AFMParser 57 { 58 61 public static final String COMMENT = "Comment"; 62 65 public static final String START_FONT_METRICS = "StartFontMetrics"; 66 69 public static final String END_FONT_METRICS = "EndFontMetrics"; 70 73 public static final String FONT_NAME = "FontName"; 74 77 public static final String FULL_NAME = "FullName"; 78 81 public static final String FAMILY_NAME = "FamilyName"; 82 85 public static final String WEIGHT = "Weight"; 86 89 public static final String FONT_BBOX = "FontBBox"; 90 93 public static final String VERSION = "Version"; 94 97 public static final String NOTICE = "Notice"; 98 101 public static final String ENCODING_SCHEME = "EncodingScheme"; 102 105 public static final String MAPPING_SCHEME = "MappingScheme"; 106 109 public static final String ESC_CHAR = "EscChar"; 110 113 public static final String CHARACTER_SET = "CharacterSet"; 114 117 public static final String CHARACTERS = "Characters"; 118 121 public static final String IS_BASE_FONT = "IsBaseFont"; 122 125 public static final String V_VECTOR = "VVector"; 126 129 public static final String IS_FIXED_V = "IsFixedV"; 130 133 public static final String CAP_HEIGHT = "CapHeight"; 134 137 public static final String X_HEIGHT = "XHeight"; 138 141 public static final String ASCENDER = "Ascender"; 142 145 public static final String DESCENDER = "Descender"; 146 147 150 public static final String UNDERLINE_POSITION = "UnderlinePosition"; 151 154 public static final String UNDERLINE_THICKNESS = "UnderlineThickness"; 155 158 public static final String ITALIC_ANGLE = "ItalicAngle"; 159 162 public static final String CHAR_WIDTH = "CharWidth"; 163 166 public static final String IS_FIXED_PITCH = "IsFixedPitch"; 167 170 public static final String START_CHAR_METRICS = "StartCharMetrics"; 171 174 public static final String END_CHAR_METRICS = "EndCharMetrics"; 175 178 public static final String CHARMETRICS_C = "C"; 179 182 public static final String CHARMETRICS_CH = "CH"; 183 186 public static final String CHARMETRICS_WX = "WX"; 187 190 public static final String CHARMETRICS_W0X = "W0X"; 191 194 public static final String CHARMETRICS_W1X = "W1X"; 195 198 public static final String CHARMETRICS_WY = "WY"; 199 202 public static final String CHARMETRICS_W0Y = "W0Y"; 203 206 public static final String CHARMETRICS_W1Y = "W1Y"; 207 210 public static final String CHARMETRICS_W = "W"; 211 214 public static final String CHARMETRICS_W0 = "W0"; 215 218 public static final String CHARMETRICS_W1 = "W1"; 219 222 public static final String CHARMETRICS_VV = "VV"; 223 226 public static final String CHARMETRICS_N = "N"; 227 230 public static final String CHARMETRICS_B = "B"; 231 234 public static final String CHARMETRICS_L = "L"; 235 238 public static final String STD_HW = "StdHW"; 239 242 public static final String STD_VW = "StdVW"; 243 246 public static final String START_TRACK_KERN = "StartTrackKern"; 247 250 public static final String END_TRACK_KERN = "EndTrackKern"; 251 254 public static final String START_KERN_DATA = "StartKernData"; 255 258 public static final String END_KERN_DATA = "EndKernData"; 259 262 public static final String START_KERN_PAIRS = "StartKernPairs"; 263 266 public static final String END_KERN_PAIRS = "EndKernPairs"; 267 270 public static final String START_KERN_PAIRS0 = "StartKernPairs0"; 271 274 public static final String START_KERN_PAIRS1 = "StartKernPairs1"; 275 278 public static final String START_COMPOSITES = "StartComposites"; 279 282 public static final String END_COMPOSITES = "EndComposites"; 283 286 public static final String CC = "CC"; 287 290 public static final String PCC = "PCC"; 291 294 public static final String KERN_PAIR_KP = "KP"; 295 298 public static final String KERN_PAIR_KPH = "KPH"; 299 302 public static final String KERN_PAIR_KPX = "KPX"; 303 306 public static final String KERN_PAIR_KPY = "KPY"; 307 308 private static final int BITS_IN_HEX = 16; 309 310 311 private InputStream input; 312 private FontMetric result; 313 314 322 public static void main( String [] args ) throws IOException 323 { 324 java.io.File afmDir = new java.io.File ( "Resources/afm" ); 325 java.io.File [] files = afmDir.listFiles(); 326 for( int i=0; i< files.length; i++ ) 327 { 328 if( files[i].getPath().endsWith( ".AFM" ) ) 329 { 330 long start = System.currentTimeMillis(); 331 java.io.FileInputStream input = new java.io.FileInputStream ( files[i] ); 332 AFMParser parser = new AFMParser( input ); 333 parser.parse(); 334 long stop = System.currentTimeMillis(); 335 System.out.println( "Parsing:" + files[i].getPath() + " " + (stop-start) ); 336 } 337 } 338 } 339 340 345 public AFMParser( InputStream in ) 346 { 347 input = in; 348 } 349 350 356 public void parse() throws IOException 357 { 358 result = parseFontMetric(); 359 } 360 361 366 public FontMetric getResult() 367 { 368 return result; 369 } 370 371 378 private FontMetric parseFontMetric() throws IOException 379 { 380 FontMetric fontMetrics = new FontMetric(); 381 String startFontMetrics = readString(); 382 if( !START_FONT_METRICS.equals( startFontMetrics ) ) 383 { 384 throw new IOException ( "Error: The AFM file should start with " + START_FONT_METRICS + 385 " and not '" + startFontMetrics + "'" ); 386 } 387 fontMetrics.setAFMVersion( readFloat() ); 388 String nextCommand = null; 389 while( !END_FONT_METRICS.equals( (nextCommand = readString() ) ) ) 390 { 391 if( FONT_NAME.equals( nextCommand ) ) 392 { 393 fontMetrics.setFontName( readLine() ); 394 } 395 else if( FULL_NAME.equals( nextCommand ) ) 396 { 397 fontMetrics.setFullName( readLine() ); 398 } 399 else if( FAMILY_NAME.equals( nextCommand ) ) 400 { 401 fontMetrics.setFamilyName( readLine() ); 402 } 403 else if( WEIGHT.equals( nextCommand ) ) 404 { 405 fontMetrics.setWeight( readLine() ); 406 } 407 else if( FONT_BBOX.equals( nextCommand ) ) 408 { 409 BoundingBox bBox = new BoundingBox(); 410 bBox.setLowerLeftX( readFloat() ); 411 bBox.setLowerLeftY( readFloat() ); 412 bBox.setUpperRightX( readFloat() ); 413 bBox.setUpperRightY( readFloat() ); 414 fontMetrics.setFontBBox( bBox ); 415 } 416 else if( VERSION.equals( nextCommand ) ) 417 { 418 fontMetrics.setFontVersion( readLine() ); 419 } 420 else if( NOTICE.equals( nextCommand ) ) 421 { 422 fontMetrics.setNotice( readLine() ); 423 } 424 else if( ENCODING_SCHEME.equals( nextCommand ) ) 425 { 426 fontMetrics.setEncodingScheme( readLine() ); 427 } 428 else if( MAPPING_SCHEME.equals( nextCommand ) ) 429 { 430 fontMetrics.setMappingScheme( readInt() ); 431 } 432 else if( ESC_CHAR.equals( nextCommand ) ) 433 { 434 fontMetrics.setEscChar( readInt() ); 435 } 436 else if( CHARACTER_SET.equals( nextCommand ) ) 437 { 438 fontMetrics.setCharacterSet( readLine() ); 439 } 440 else if( CHARACTERS.equals( nextCommand ) ) 441 { 442 fontMetrics.setCharacters( readInt() ); 443 } 444 else if( IS_BASE_FONT.equals( nextCommand ) ) 445 { 446 fontMetrics.setIsBaseFont( readBoolean() ); 447 } 448 else if( V_VECTOR.equals( nextCommand ) ) 449 { 450 float[] vector = new float[2]; 451 vector[0] = readFloat(); 452 vector[1] = readFloat(); 453 fontMetrics.setVVector( vector ); 454 } 455 else if( IS_FIXED_V.equals( nextCommand ) ) 456 { 457 fontMetrics.setIsFixedV( readBoolean() ); 458 } 459 else if( CAP_HEIGHT.equals( nextCommand ) ) 460 { 461 fontMetrics.setCapHeight( readFloat() ); 462 } 463 else if( X_HEIGHT.equals( nextCommand ) ) 464 { 465 fontMetrics.setXHeight( readFloat() ); 466 } 467 else if( ASCENDER.equals( nextCommand ) ) 468 { 469 fontMetrics.setAscender( readFloat() ); 470 } 471 else if( DESCENDER.equals( nextCommand ) ) 472 { 473 fontMetrics.setDescender( readFloat() ); 474 } 475 else if( STD_HW.equals( nextCommand ) ) 476 { 477 fontMetrics.setStandardHorizontalWidth( readFloat() ); 478 } 479 else if( STD_VW.equals( nextCommand ) ) 480 { 481 fontMetrics.setStandardVerticalWidth( readFloat() ); 482 } 483 else if( COMMENT.equals( nextCommand ) ) 484 { 485 fontMetrics.addComment( readLine() ); 486 } 487 else if( UNDERLINE_POSITION.equals( nextCommand ) ) 488 { 489 fontMetrics.setUnderlinePosition( readFloat() ); 490 } 491 else if( UNDERLINE_THICKNESS.equals( nextCommand ) ) 492 { 493 fontMetrics.setUnderlineThickness( readFloat() ); 494 } 495 else if( ITALIC_ANGLE.equals( nextCommand ) ) 496 { 497 fontMetrics.setItalicAngle( readFloat() ); 498 } 499 else if( CHAR_WIDTH.equals( nextCommand ) ) 500 { 501 float[] widths = new float[2]; 502 widths[0] = readFloat(); 503 widths[1] = readFloat(); 504 fontMetrics.setCharWidth( widths ); 505 } 506 else if( IS_FIXED_PITCH.equals( nextCommand ) ) 507 { 508 fontMetrics.setFixedPitch( readBoolean() ); 509 } 510 else if( START_CHAR_METRICS.equals( nextCommand ) ) 511 { 512 int count = readInt(); 513 for( int i=0; i<count; i++ ) 514 { 515 CharMetric charMetric = parseCharMetric(); 516 fontMetrics.addCharMetric( charMetric ); 517 } 518 String end = readString(); 519 if( !end.equals( END_CHAR_METRICS ) ) 520 { 521 throw new IOException ( "Error: Expected '" + END_CHAR_METRICS + "' actual '" + 522 end + "'" ); 523 } 524 } 525 else if( START_COMPOSITES.equals( nextCommand ) ) 526 { 527 int count = readInt(); 528 for( int i=0; i<count; i++ ) 529 { 530 Composite part = parseComposite(); 531 fontMetrics.addComposite( part ); 532 } 533 String end = readString(); 534 if( !end.equals( END_COMPOSITES ) ) 535 { 536 throw new IOException ( "Error: Expected '" + END_COMPOSITES + "' actual '" + 537 end + "'" ); 538 } 539 } 540 else if( START_KERN_DATA.equals( nextCommand ) ) 541 { 542 parseKernData( fontMetrics ); 543 } 544 else 545 { 546 throw new IOException ( "Unknown AFM key '" + nextCommand + "'" ); 547 } 548 } 549 return fontMetrics; 550 } 551 552 559 private void parseKernData( FontMetric fontMetrics ) throws IOException 560 { 561 String nextCommand = null; 562 while( !(nextCommand = readString()).equals( END_KERN_DATA ) ) 563 { 564 if( START_TRACK_KERN.equals( nextCommand ) ) 565 { 566 int count = readInt(); 567 for( int i=0; i<count; i++ ) 568 { 569 TrackKern kern = new TrackKern(); 570 kern.setDegree( readInt() ); 571 kern.setMinPointSize( readFloat() ); 572 kern.setMinKern( readFloat() ); 573 kern.setMaxPointSize( readFloat() ); 574 kern.setMaxKern( readFloat() ); 575 fontMetrics.addTrackKern( kern ); 576 } 577 String end = readString(); 578 if( !end.equals( END_TRACK_KERN ) ) 579 { 580 throw new IOException ( "Error: Expected '" + END_TRACK_KERN + "' actual '" + 581 end + "'" ); 582 } 583 } 584 else if( START_KERN_PAIRS.equals( nextCommand ) ) 585 { 586 int count = readInt(); 587 for( int i=0; i<count; i++ ) 588 { 589 KernPair pair = parseKernPair(); 590 fontMetrics.addKernPair( pair ); 591 } 592 String end = readString(); 593 if( !end.equals( END_KERN_PAIRS ) ) 594 { 595 throw new IOException ( "Error: Expected '" + END_KERN_PAIRS + "' actual '" + 596 end + "'" ); 597 } 598 } 599 else if( START_KERN_PAIRS0.equals( nextCommand ) ) 600 { 601 int count = readInt(); 602 for( int i=0; i<count; i++ ) 603 { 604 KernPair pair = parseKernPair(); 605 fontMetrics.addKernPair0( pair ); 606 } 607 String end = readString(); 608 if( !end.equals( END_KERN_PAIRS ) ) 609 { 610 throw new IOException ( "Error: Expected '" + END_KERN_PAIRS + "' actual '" + 611 end + "'" ); 612 } 613 } 614 else if( START_KERN_PAIRS1.equals( nextCommand ) ) 615 { 616 int count = readInt(); 617 for( int i=0; i<count; i++ ) 618 { 619 KernPair pair = parseKernPair(); 620 fontMetrics.addKernPair1( pair ); 621 } 622 String end = readString(); 623 if( !end.equals( END_KERN_PAIRS ) ) 624 { 625 throw new IOException ( "Error: Expected '" + END_KERN_PAIRS + "' actual '" + 626 end + "'" ); 627 } 628 } 629 else 630 { 631 throw new IOException ( "Unknown kerning data type '" + nextCommand + "'" ); 632 } 633 } 634 } 635 636 643 private KernPair parseKernPair() throws IOException 644 { 645 KernPair kernPair = new KernPair(); 646 String cmd = readString(); 647 if( KERN_PAIR_KP.equals( cmd ) ) 648 { 649 String first = readString(); 650 String second = readString(); 651 float x = readFloat(); 652 float y = readFloat(); 653 kernPair.setFirstKernCharacter( first ); 654 kernPair.setSecondKernCharacter( second ); 655 kernPair.setX( x ); 656 kernPair.setY( y ); 657 } 658 else if( KERN_PAIR_KPH.equals( cmd ) ) 659 { 660 String first = hexToString( readString() ); 661 String second = hexToString( readString() ); 662 float x = readFloat(); 663 float y = readFloat(); 664 kernPair.setFirstKernCharacter( first ); 665 kernPair.setSecondKernCharacter( second ); 666 kernPair.setX( x ); 667 kernPair.setY( y ); 668 } 669 else if( KERN_PAIR_KPX.equals( cmd ) ) 670 { 671 String first = readString(); 672 String second = readString(); 673 float x = readFloat(); 674 kernPair.setFirstKernCharacter( first ); 675 kernPair.setSecondKernCharacter( second ); 676 kernPair.setX( x ); 677 kernPair.setY( 0 ); 678 } 679 else if( KERN_PAIR_KPY.equals( cmd ) ) 680 { 681 String first = readString(); 682 String second = readString(); 683 float y = readFloat(); 684 kernPair.setFirstKernCharacter( first ); 685 kernPair.setSecondKernCharacter( second ); 686 kernPair.setX( 0 ); 687 kernPair.setY( y ); 688 } 689 else 690 { 691 throw new IOException ( "Error expected kern pair command actual='" + cmd + "'" ); 692 } 693 return kernPair; 694 } 695 696 705 private String hexToString( String hexString ) throws IOException 706 { 707 if( hexString.length() < 2 ) 708 { 709 throw new IOException ( "Error: Expected hex string of length >= 2 not='" + hexString ); 710 } 711 if( hexString.charAt( 0 ) != '<' || 712 hexString.charAt( hexString.length() -1 ) != '>' ) 713 { 714 throw new IOException ( "String should be enclosed by angle brackets '" + hexString+ "'" ); 715 } 716 hexString = hexString.substring( 1, hexString.length() -1 ); 717 byte[] data = new byte[ (int)(hexString.length() / 2) ]; 718 for( int i=0; i<hexString.length(); i+=2 ) 719 { 720 String hex = "" + hexString.charAt( i ) + hexString.charAt( i+1 ); 721 try 722 { 723 data[ i / 2 ] = (byte)Integer.parseInt( hex, BITS_IN_HEX ); 724 } 725 catch( NumberFormatException e ) 726 { 727 throw new IOException ( "Error parsing AFM file:" + e ); 728 } 729 } 730 return new String ( data ); 731 } 732 733 740 private Composite parseComposite() throws IOException 741 { 742 Composite composite = new Composite(); 743 String partData = readLine(); 744 StringTokenizer tokenizer = new StringTokenizer ( partData, " ;" ); 745 746 747 String cc = tokenizer.nextToken(); 748 if( !cc.equals( CC ) ) 749 { 750 throw new IOException ( "Expected '" + CC + "' actual='" + cc + "'" ); 751 } 752 String name = tokenizer.nextToken(); 753 composite.setName( name ); 754 755 int partCount; 756 try 757 { 758 partCount = Integer.parseInt( tokenizer.nextToken() ); 759 } 760 catch( NumberFormatException e ) 761 { 762 throw new IOException ( "Error parsing AFM document:" + e ); 763 } 764 for( int i=0; i<partCount; i++ ) 765 { 766 CompositePart part = new CompositePart(); 767 String pcc = tokenizer.nextToken(); 768 if( !pcc.equals( PCC ) ) 769 { 770 throw new IOException ( "Expected '" + PCC + "' actual='" + pcc + "'" ); 771 } 772 String partName = tokenizer.nextToken(); 773 try 774 { 775 int x = Integer.parseInt( tokenizer.nextToken() ); 776 int y = Integer.parseInt( tokenizer.nextToken() ); 777 778 part.setName( partName ); 779 part.setXDisplacement( x ); 780 part.setYDisplacement( y ); 781 composite.addPart( part ); 782 } 783 catch( NumberFormatException e ) 784 { 785 throw new IOException ( "Error parsing AFM document:" + e ); 786 } 787 } 788 return composite; 789 } 790 791 798 private CharMetric parseCharMetric() throws IOException 799 { 800 CharMetric charMetric = new CharMetric(); 801 String metrics = readLine(); 802 StringTokenizer metricsTokenizer = new StringTokenizer ( metrics ); 803 try 804 { 805 while( metricsTokenizer.hasMoreTokens() ) 806 { 807 String nextCommand = metricsTokenizer.nextToken(); 808 if( nextCommand.equals( CHARMETRICS_C ) ) 809 { 810 String charCode = metricsTokenizer.nextToken(); 811 charMetric.setCharacterCode( Integer.parseInt( charCode ) ); 812 verifySemicolon( metricsTokenizer ); 813 } 814 else if( nextCommand.equals( CHARMETRICS_CH ) ) 815 { 816 String charCode = metricsTokenizer.nextToken(); 819 charMetric.setCharacterCode( Integer.parseInt( charCode, BITS_IN_HEX ) ); 820 verifySemicolon( metricsTokenizer ); 821 } 822 else if( nextCommand.equals( CHARMETRICS_WX ) ) 823 { 824 String wx = metricsTokenizer.nextToken(); 825 charMetric.setWx( Float.parseFloat( wx ) ); 826 verifySemicolon( metricsTokenizer ); 827 } 828 else if( nextCommand.equals( CHARMETRICS_W0X ) ) 829 { 830 String w0x = metricsTokenizer.nextToken(); 831 charMetric.setW0x( Float.parseFloat( w0x ) ); 832 verifySemicolon( metricsTokenizer ); 833 } 834 else if( nextCommand.equals( CHARMETRICS_W1X ) ) 835 { 836 String w1x = metricsTokenizer.nextToken(); 837 charMetric.setW0x( Float.parseFloat( w1x ) ); 838 verifySemicolon( metricsTokenizer ); 839 } 840 else if( nextCommand.equals( CHARMETRICS_WY ) ) 841 { 842 String wy = metricsTokenizer.nextToken(); 843 charMetric.setWy( Float.parseFloat( wy ) ); 844 verifySemicolon( metricsTokenizer ); 845 } 846 else if( nextCommand.equals( CHARMETRICS_W0Y ) ) 847 { 848 String w0y = metricsTokenizer.nextToken(); 849 charMetric.setW0y( Float.parseFloat( w0y ) ); 850 verifySemicolon( metricsTokenizer ); 851 } 852 else if( nextCommand.equals( CHARMETRICS_W1Y ) ) 853 { 854 String w1y = metricsTokenizer.nextToken(); 855 charMetric.setW0y( Float.parseFloat( w1y ) ); 856 verifySemicolon( metricsTokenizer ); 857 } 858 else if( nextCommand.equals( CHARMETRICS_W ) ) 859 { 860 String w0 = metricsTokenizer.nextToken(); 861 String w1 = metricsTokenizer.nextToken(); 862 float[] w = new float[2]; 863 w[0] = Float.parseFloat( w0 ); 864 w[1] = Float.parseFloat( w1 ); 865 charMetric.setW( w ); 866 verifySemicolon( metricsTokenizer ); 867 } 868 else if( nextCommand.equals( CHARMETRICS_W0 ) ) 869 { 870 String w00 = metricsTokenizer.nextToken(); 871 String w01 = metricsTokenizer.nextToken(); 872 float[] w0 = new float[2]; 873 w0[0] = Float.parseFloat( w00 ); 874 w0[1] = Float.parseFloat( w01 ); 875 charMetric.setW0( w0 ); 876 verifySemicolon( metricsTokenizer ); 877 } 878 else if( nextCommand.equals( CHARMETRICS_W1 ) ) 879 { 880 String w10 = metricsTokenizer.nextToken(); 881 String w11 = metricsTokenizer.nextToken(); 882 float[] w1 = new float[2]; 883 w1[0] = Float.parseFloat( w10 ); 884 w1[1] = Float.parseFloat( w11 ); 885 charMetric.setW1( w1 ); 886 verifySemicolon( metricsTokenizer ); 887 } 888 else if( nextCommand.equals( CHARMETRICS_VV ) ) 889 { 890 String vv0 = metricsTokenizer.nextToken(); 891 String vv1 = metricsTokenizer.nextToken(); 892 float[] vv = new float[2]; 893 vv[0] = Float.parseFloat( vv0 ); 894 vv[1] = Float.parseFloat( vv1 ); 895 charMetric.setVv( vv ); 896 verifySemicolon( metricsTokenizer ); 897 } 898 else if( nextCommand.equals( CHARMETRICS_N ) ) 899 { 900 String name = metricsTokenizer.nextToken(); 901 charMetric.setName( name ); 902 verifySemicolon( metricsTokenizer ); 903 } 904 else if( nextCommand.equals( CHARMETRICS_B ) ) 905 { 906 String llx = metricsTokenizer.nextToken(); 907 String lly = metricsTokenizer.nextToken(); 908 String urx = metricsTokenizer.nextToken(); 909 String ury = metricsTokenizer.nextToken(); 910 BoundingBox box = new BoundingBox(); 911 box.setLowerLeftX( Float.parseFloat( llx ) ); 912 box.setLowerLeftY( Float.parseFloat( lly ) ); 913 box.setUpperRightX( Float.parseFloat( urx ) ); 914 box.setUpperRightY( Float.parseFloat( ury ) ); 915 charMetric.setBoundingBox( box ); 916 verifySemicolon( metricsTokenizer ); 917 } 918 else if( nextCommand.equals( CHARMETRICS_L ) ) 919 { 920 String successor = metricsTokenizer.nextToken(); 921 String ligature = metricsTokenizer.nextToken(); 922 Ligature lig = new Ligature(); 923 lig.setSuccessor( successor ); 924 lig.setLigature( ligature ); 925 charMetric.addLigature( lig ); 926 verifySemicolon( metricsTokenizer ); 927 } 928 else 929 { 930 throw new IOException ( "Unknown CharMetrics command '" + nextCommand + "'" ); 931 } 932 } 933 } 934 catch( NumberFormatException e ) 935 { 936 throw new IOException ( "Error: Corrupt AFM document:" + e ); 937 } 938 return charMetric; 939 } 940 941 948 private void verifySemicolon( StringTokenizer tokenizer ) throws IOException 949 { 950 if( tokenizer.hasMoreTokens() ) 951 { 952 String semicolon = tokenizer.nextToken(); 953 if( !semicolon.equals( ";" ) ) 954 { 955 throw new IOException ( "Error: Expected semicolon in stream actual='" + 956 semicolon + "'" ); 957 } 958 } 959 else 960 { 961 throw new IOException ( "CharMetrics is missing a semicolon after a command" ); 962 } 963 } 964 965 970 private boolean readBoolean() throws IOException 971 { 972 String theBoolean = readString(); 973 return Boolean.valueOf( theBoolean ).booleanValue(); 974 } 975 976 981 private int readInt() throws IOException 982 { 983 String theInt = readString(); 984 try 985 { 986 return Integer.parseInt( theInt ); 987 } 988 catch( NumberFormatException e ) 989 { 990 throw new IOException ( "Error parsing AFM document:" + e ); 991 } 992 } 993 994 999 private float readFloat() throws IOException 1000 { 1001 String theFloat = readString(); 1002 return Float.parseFloat( theFloat ); 1003 } 1004 1005 1010 private String readLine() throws IOException 1011 { 1012 StringBuffer buf = new StringBuffer (); 1014 int nextByte = input.read(); 1015 while( isWhitespace( nextByte ) ) 1016 { 1017 nextByte = input.read(); 1018 } 1020 buf.append( (char)nextByte ); 1021 1022 while( !isEOL(nextByte = input.read()) ) 1024 { 1025 buf.append( (char)nextByte ); 1026 } 1027 return buf.toString(); 1028 } 1029 1030 1037 private String readString() throws IOException 1038 { 1039 StringBuffer buf = new StringBuffer (); 1041 int nextByte = input.read(); 1042 while( isWhitespace( nextByte ) ) 1043 { 1044 nextByte = input.read(); 1045 } 1047 buf.append( (char)nextByte ); 1048 1049 while( !isWhitespace(nextByte = input.read()) ) 1051 { 1052 buf.append( (char)nextByte ); 1053 } 1054 return buf.toString(); 1055 } 1056 1057 1064 private boolean isEOL( int character ) 1065 { 1066 return character == 0x0D || 1067 character == 0x0A; 1068 } 1069 1070 1077 private boolean isWhitespace( int character ) 1078 { 1079 return character == (int)' ' || 1080 character == (int)'\t' || 1081 character == 0x0D || 1082 character == 0x0A; 1083 } 1084} | Popular Tags |