/* Ċ Ġ* ĠCopyright Ġ 2 0 1 8 ĠPoly ĠForest Ċ Ġ* Ċ Ġ* ĠLicensed Ġunder Ġthe ĠApache ĠLicense , ĠVersion Ġ 2 . 0 Ġ( the Ġ" License "); Ċ Ġ* Ġyou Ġmay Ġnot Ġuse Ġthis Ġfile Ġexcept Ġin Ġcompliance Ġwith Ġthe ĠLicense . Ċ Ġ* ĠYou Ġmay Ġobtain Ġa Ġcopy Ġof Ġthe ĠLicense Ġat Ċ Ġ* Ċ Ġ* ĠĠĠĠ Ġhttp :// www . apache . org / licenses / LICENSE - 2 . 0 Ċ Ġ* Ċ Ġ* ĠUnless Ġrequired Ġby Ġapplicable Ġlaw Ġor Ġagreed Ġto Ġin Ġwriting , Ġsoftware Ċ Ġ* Ġdistributed Ġunder Ġthe ĠLicense Ġis Ġdistributed Ġon Ġan Ġ" AS ĠIS " ĠBASIS , Ċ Ġ* ĠWITHOUT ĠWARRANTIES ĠOR ĠCONDITIONS ĠOF ĠANY ĠKIND , Ġeither Ġexpress Ġor Ġimplied . Ċ Ġ* ĠSee Ġthe ĠLicense Ġfor Ġthe Ġspecific Ġlanguage Ġgoverning Ġpermissions Ġand Ċ Ġ* Ġlimitations Ġunder Ġthe ĠLicense . Ċ Ġ*/ Ċ Ċ package Ġcom . ac orn ui . component . text Ċ Ċ import Ġcom . ac orn ui . action . Decorator Ċ import Ġcom . ac orn ui . component . text . Glyph Data . Companion . EMPTY _ CHAR Ċ import Ġcom . ac orn ui . component . text . Glyph Data . Companion . UNKNOWN _ CHAR Ċ import Ġcom . ac orn ui . math . Int Rectangle Ċ import Ġcom . ac orn ui . string . String Reader Ċ import Ġcom . ac orn ui . core . replace 2 Ċ import Ġcom . ac orn ui . math . Int Pad Ċ import Ġkotlin . math . abs Ċ Ċ /** Ċ Ġ* Ġhttp :// www . ange l code . com / products / bm font / doc / file _ format . html Ċ Ġ* Ċ Ġ* Ġ@ author Ġnb ily k Ċ Ġ*/ Ċ object ĠAn gel Code Parser Ġ: ĠDecor ator < String , ĠBitmap Font Data > Ġ{ ĊĊ ĉ fun Ġparse ( str : ĠString ): ĠBitmap Font Data Ġ{ Ċĉ ĉ val Ġparser Ġ= ĠString Reader ( str ) ĊĊĉ ĉ // ĠInfo Ċĉ ĉ parser . white () Ċĉ ĉ parser . consume String (" info ") ĊĊĉ ĉ val Ġface Ġ= Ġparse Quoted String Prop ( parser , Ġ" face ") Ċĉ ĉ val Ġsize Ġ= Ġabs ( parseInt Prop ( parser , Ġ" size ")) Ċĉ ĉ val Ġbold Ġ= Ġparse Bool Prop ( parser , Ġ" bold ") Ċĉ ĉ val Ġitalic Ġ= Ġparse Bool Prop ( parser , Ġ" italic ") Ċĉ ĉ val Ġcharset Ġ= Ġparse Quoted String Prop ( parser , Ġ" charset ") Ċĉ ĉ val Ġunicode Ġ= Ġparse Bool Prop ( parser , Ġ" unicode ") Ċĉ ĉ val Ġstretch H Ġ= ĠparseInt Prop ( parser , Ġ" stretch H ") Ċĉ ĉ val Ġsmooth Ġ= Ġparse Bool Prop ( parser , Ġ" smooth ") Ċĉ ĉ val Ġant ialias ing Ġ= ĠparseInt Prop ( parser , Ġ" aa ") Ċĉ ĉ val Ġpadding Ġ= ĠInt Pad ( parseInt Array Prop ( parser , Ġ" padding ")) Ċĉ ĉ val Ġspacing Ġ= ĠparseInt Array Prop ( parser , Ġ" spacing ") ĊĊĉ ĉ val Ġinfo Ġ= ĠBitmap Font Info ( Ċĉĉĉ ĉ face , Ċĉĉĉ ĉ size , Ċĉĉĉ ĉ bold , Ċĉĉĉ ĉ italic , Ċĉĉĉ ĉ charset , Ċĉĉĉ ĉ unicode , Ċĉĉĉ ĉ stretch H , Ċĉĉĉ ĉ smooth , Ċĉĉĉ ĉ ant ialias ing , Ċĉĉĉ ĉ padding , Ċĉĉĉ ĉ spacing [ 0 ], Ċĉĉĉ ĉ spacing [ 1 ] Ċĉ ĉ ) ĊĊĉ ĉ // ĠCommon Ċĉ ĉ nextLine ( parser ) Ċĉ ĉ parser . consume String (" common ") Ċĉ ĉ val Ġline Height Ġ= ĠparseInt Prop ( parser , Ġ" line Height ") Ċĉ ĉ val Ġbaseline Ġ= ĠparseInt Prop ( parser , Ġ" base ") Ċĉ ĉ val Ġpage W Ġ= ĠparseInt Prop ( parser , Ġ" scale W ") Ċĉ ĉ val Ġpage H Ġ= ĠparseInt Prop ( parser , Ġ" scale H ") Ċĉ ĉ val Ġtotal Pages Ġ= ĠparseInt Prop ( parser , Ġ" pages ") ĊĊĉ ĉ val Ġpages Ġ= ĠArray ( total Pages ) Ġ{ Ċĉĉ ĉ // ĠRead Ġeach Ġ" page " Ġinfo Ġline . Ċĉĉ ĉ nextLine ( parser ) Ċĉĉ ĉ if Ġ(! parser . consume String (" page ")) Ġthrow ĠException (" Missing Ġpage Ġdefinition .") ĊĊĉĉ ĉ val Ġid Ġ= ĠparseInt Prop ( parser , Ġ" id ") Ċĉĉ ĉ val ĠfileName : ĠString Ġ= Ġparse Quoted String Prop ( parser , Ġ" file ") Ċĉĉ ĉ val Ġimage Path Ġ= ĠfileName . replace 2 ('\\ ', Ġ'/') Ċĉĉ ĉ Bitmap Font Page Data ( id , Ġimage Path ) Ċĉ ĉ } ĊĊĉ ĉ // ĠCh ars Ċĉ ĉ nextLine ( parser ) Ċĉ ĉ if Ġ(! parser . consume String (" chars ")) Ġthrow ĠException (" Expected Ġchars Ġblock ") Ċĉ ĉ // ĠThe Ġchars Ġcount Ġfrom ĠHi ero Ġis Ġoff , Ġso Ġwe 're Ġnot Ġgoing Ġto Ġuse Ġit . Ċĉ ĉ val Ġglyph s Ġ= ĠHashMap < Char , ĠGlyph Data >() Ċĉ ĉ val Ġker nings Ġ= ĠHashMap < Char , ĠMutable Map < Char , ĠInt >>() ĊĊĉ ĉ // ĠRead Ġeach Ġglyph Ġdefinition . Ċĉ ĉ while Ġ( true ) Ġ{ Ċĉĉ ĉ nextLine ( parser ) Ċĉĉ ĉ if Ġ(! parser . consume String (" char ")) Ġbreak ĊĊĉĉ ĉ val Ġch Ġ= ĠparseInt Prop ( parser , Ġ" id "). to Char () Ċĉĉ ĉ if Ġ( ch Ġ> ĠChar . MAX _ SUR RO GATE ) Ġcontinue ĊĊĉĉ ĉ val Ġregion X Ġ= ĠparseInt Prop ( parser , Ġ" x ") Ċĉĉ ĉ val Ġregion Y Ġ= ĠparseInt Prop ( parser , Ġ" y ") Ċĉĉ ĉ val Ġregion W Ġ= ĠparseInt Prop ( parser , Ġ" width ") Ċĉĉ ĉ val Ġregion H Ġ= ĠparseInt Prop ( parser , Ġ" height ") Ċĉĉ ĉ val Ġoffset X Ġ= ĠparseInt Prop ( parser , Ġ" x offset ") Ċĉĉ ĉ val Ġoffset Y Ġ= ĠparseInt Prop ( parser , Ġ" y offset ") Ċĉĉ ĉ val Ġx Advance Ġ= ĠparseInt Prop ( parser , Ġ" x advance ") Ċĉĉ ĉ val Ġpage Ġ= ĠparseInt Prop ( parser , Ġ" page ") Ċĉĉ ĉ val Ġker ning Ġ= ĠHashMap < Char , ĠInt >() Ċĉĉ ĉ ker nings [ ch ] Ġ= Ġker ning Ċĉĉ ĉ glyph s [ ch ] Ġ= ĠGlyph Data ( Ċĉĉĉĉ ĉ char Ġ= Ġch , Ċĉĉĉĉ ĉ region Ġ= ĠInt Rectangle ( region X , Ġregion Y , Ġregion W , Ġregion H ). reduce ( info . padding ), Ċĉĉĉĉ ĉ offset X Ġ= Ġoffset X Ġ+ Ġinfo . padding . left , Ċĉĉĉĉ ĉ offset Y Ġ= Ġoffset Y Ġ+ Ġinfo . padding . top , Ċĉĉĉĉ ĉ advance X Ġ= Ġx Advance , Ċĉĉĉĉ ĉ page Ġ= Ġpage , Ċĉĉĉĉ ĉ ker ning Ġ= Ġker ning Ċĉĉ ĉ ). clamp Region ( page W , Ġpage H ) Ċĉ ĉ } ĊĊĉ ĉ parser . consume String (" ker nings ") ĊĊĉ ĉ while Ġ( true ) Ġ{ Ċĉĉ ĉ nextLine ( parser ) Ċĉĉ ĉ if Ġ(! parser . consume String (" ker ning ")) Ġbreak ĊĊĉĉ ĉ val Ġfirst Ġ= ĠparseInt Prop ( parser , Ġ" first ") Ċĉĉ ĉ val Ġsecond Ġ= ĠparseInt Prop ( parser , Ġ" second ") Ċĉĉ ĉ if Ġ( first Ġ< Ġ 0 Ġ|| Ġsecond Ġ< Ġ 0 ) Ġcontinue Ċĉĉ ĉ val Ġamount Ġ= ĠparseInt Prop ( parser , Ġ" amount ") Ċĉĉ ĉ if Ġ( glyph s . containsKey ( first . to Char ())) Ġ{ Ċĉĉĉ ĉ // ĠKer ning Ġpairs Ġmay Ġexist Ġfor Ġglyph s Ġnot Ġcontained Ġin Ġthe Ġfont . Ċĉĉĉ ĉ ker nings [ first . to Char ()] ! ![ second . to Char ()] Ġ= Ġamount Ċĉĉ ĉ } Ċĉ ĉ } ĊĊĉ ĉ glyph s . add Missing Common Glyph s () ĊĊĉ ĉ return ĠBitmap Font Data ( Ċĉĉĉ ĉ info Ġ= Ġinfo , Ċĉĉĉ ĉ pages Ġ= Ġpages . toList (), Ċĉĉĉ ĉ glyph s Ġ= Ġglyph s , Ċĉĉĉ ĉ line Height Ġ= Ġline Height , Ċĉĉĉ ĉ baseline Ġ= Ġbaseline , Ċĉĉĉ ĉ page W Ġ= Ġpage W , Ċĉĉĉ ĉ page H Ġ= Ġpage H Ċĉ ĉ ) Ċ ĉ } ĊĊ ĉ private Ġfun ĠMutable Map < Char , ĠGlyph Data >. add Missing Common Glyph s () Ġ{ Ċĉ ĉ var Ġspace Ġ= Ġthis [' Ġ'] Ċĉ ĉ if Ġ( space Ġ== Ġnull ) Ġ{ Ċĉĉ ĉ var Ġcopy Ġ= Ġthis [' n '] Ċĉĉ ĉ if Ġ( copy Ġ== Ġnull ) Ġcopy Ġ= Ġthis . values . first OrNull () Ċĉĉ ĉ if Ġ( copy Ġ== Ġnull ) Ġreturn Ġ// ĠThere 's Ġno Ġhope Ċĉĉ ĉ space Ġ= ĠGlyph Data ( char Ġ= Ġ' Ġ', Ġadvance X Ġ= Ġcopy . advance X ) Ċĉĉ ĉ this [' Ġ'] Ġ= Ġspace Ċĉ ĉ } Ċĉ ĉ for Ġ( char Ġin ĠarrayOf ('\ t ', Ġ'\ n ', Ġ'\ r ')) Ġ{ Ċĉĉ ĉ // ĠIn visible Ġcharacters Ġthat Ġtake Ġup Ġno Ġspace . Ċĉĉ ĉ if Ġ( this [ char ] Ġ== Ġnull ) Ġ{ Ċĉĉĉ ĉ this [ char ] Ġ= ĠGlyph Data ( char ) Ċĉĉ ĉ } Ċĉ ĉ } Ċĉ ĉ this [ EMPTY _ CHAR ] Ġ= ĠGlyph Data ( EMPTY _ CHAR ) Ċĉ ĉ val Ġnb sp Char Ġ= Ġ' ï¿½ ' Ċĉ ĉ if Ġ( this [ nbsp Char ] Ġ== Ġnull ) Ġ{ Ċĉĉ ĉ this [ nbsp Char ] Ġ= Ġspace . copy ( char Ġ= Ġnb sp Char ) Ċĉ ĉ } Ċĉ ĉ this [ UNKNOWN _ CHAR ] Ġ= Ġ( this [' ? '] Ġ?: Ġspace ). copy ( char Ġ= ĠUNKNOWN _ CHAR ) Ċ ĉ } ĊĊ ĉ private Ġfun Ġnext Line ( parser : ĠString Reader ): ĠBoolean Ġ{ Ċĉ ĉ val Ġfound Ġ= Ġparser . consume Through ('\ n ') Ċĉ ĉ if Ġ( found ) Ġparser . white () Ċĉ ĉ return Ġfound Ċ ĉ } ĊĊ ĉ private Ġfun ĠparseFloat Prop ( parser : ĠString Reader , Ġproperty : ĠString ): ĠFloat Ġ{ Ċĉ ĉ consume Property ( parser , Ġproperty ) Ċĉ ĉ return Ġparser . get Float () !! Ċ ĉ } ĊĊ ĉ private Ġfun Ġparse Bool Prop ( parser : ĠString Reader , Ġproperty : ĠString ): ĠBoolean Ġ{ Ċĉ ĉ consume Property ( parser , Ġproperty ) Ċĉ ĉ return Ġparser . get Bool () !! Ċ ĉ } ĊĊ ĉ private Ġfun ĠparseInt Prop ( parser : ĠString Reader , Ġproperty : ĠString ): ĠInt Ġ{ Ċĉ ĉ consume Property ( parser , Ġproperty ) Ċĉ ĉ return Ġparser . getInt () !! Ċ ĉ } ĊĊ ĉ private Ġfun ĠparseInt Array Prop ( parser : ĠString Reader , Ġproperty : ĠString ): ĠArray < Int > Ġ{ Ċĉ ĉ consume Property ( parser , Ġproperty ) Ċĉ ĉ return Ġparser . not White (). split ("," ). map Ġ{ Ġit . toInt () Ġ}. to Typed Array () Ċ ĉ } ĊĊ ĉ private Ġfun Ġparse Quoted String Prop ( parser : ĠString Reader , Ġproperty : ĠString ): ĠString Ġ{ Ċĉ ĉ consume Property ( parser , Ġproperty ) Ċĉ ĉ return Ġparser . get Quoted String () !! Ċ ĉ } ĊĊ ĉ private Ġfun Ġconsume Property ( parser : ĠString Reader , Ġproperty : ĠString , Ġrequired : ĠBoolean Ġ= Ġtrue ): ĠBoolean Ġ{ Ċĉ ĉ parser . white () Ċĉ ĉ val Ġfound Ġ= Ġparser . consume String ( property ) Ċĉ ĉ if Ġ(! found ) Ġ{ Ċĉĉ ĉ if Ġ( required ) Ġthrow ĠException (" Property Ġnot Ġfound : Ġ$ property Ġat : Ġ${ parser . data . substring ( parser . position , Ġmin Of ( parser . length , Ġparser . position Ġ+ Ġ 2 0 )) }") Ċĉĉ ĉ else Ġreturn Ġfalse Ċĉ ĉ } Ċĉ ĉ parser . white () Ċĉ ĉ parser . consume Char (' =') Ċĉ ĉ parser . white () Ċĉ ĉ return Ġtrue Ċ ĉ } ĊĊ ĉ override Ġfun Ġdecor ate ( target : ĠString ): ĠBitmap Font Data Ġ= Ġparse ( target ) Ċ }