Compile.pas 326 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556255725582559256025612562256325642565256625672568256925702571257225732574257525762577257825792580258125822583258425852586258725882589259025912592259325942595259625972598259926002601260226032604260526062607260826092610261126122613261426152616261726182619262026212622262326242625262626272628262926302631263226332634263526362637263826392640264126422643264426452646264726482649265026512652265326542655265626572658265926602661266226632664266526662667266826692670267126722673267426752676267726782679268026812682268326842685268626872688268926902691269226932694269526962697269826992700270127022703270427052706270727082709271027112712271327142715271627172718271927202721272227232724272527262727272827292730273127322733273427352736273727382739274027412742274327442745274627472748274927502751275227532754275527562757275827592760276127622763276427652766276727682769277027712772277327742775277627772778277927802781278227832784278527862787278827892790279127922793279427952796279727982799280028012802280328042805280628072808280928102811281228132814281528162817281828192820282128222823282428252826282728282829283028312832283328342835283628372838283928402841284228432844284528462847284828492850285128522853285428552856285728582859286028612862286328642865286628672868286928702871287228732874287528762877287828792880288128822883288428852886288728882889289028912892289328942895289628972898289929002901290229032904290529062907290829092910291129122913291429152916291729182919292029212922292329242925292629272928292929302931293229332934293529362937293829392940294129422943294429452946294729482949295029512952295329542955295629572958295929602961296229632964296529662967296829692970297129722973297429752976297729782979298029812982298329842985298629872988298929902991299229932994299529962997299829993000300130023003300430053006300730083009301030113012301330143015301630173018301930203021302230233024302530263027302830293030303130323033303430353036303730383039304030413042304330443045304630473048304930503051305230533054305530563057305830593060306130623063306430653066306730683069307030713072307330743075307630773078307930803081308230833084308530863087308830893090309130923093309430953096309730983099310031013102310331043105310631073108310931103111311231133114311531163117311831193120312131223123312431253126312731283129313031313132313331343135313631373138313931403141314231433144314531463147314831493150315131523153315431553156315731583159316031613162316331643165316631673168316931703171317231733174317531763177317831793180318131823183318431853186318731883189319031913192319331943195319631973198319932003201320232033204320532063207320832093210321132123213321432153216321732183219322032213222322332243225322632273228322932303231323232333234323532363237323832393240324132423243324432453246324732483249325032513252325332543255325632573258325932603261326232633264326532663267326832693270327132723273327432753276327732783279328032813282328332843285328632873288328932903291329232933294329532963297329832993300330133023303330433053306330733083309331033113312331333143315331633173318331933203321332233233324332533263327332833293330333133323333333433353336333733383339334033413342334333443345334633473348334933503351335233533354335533563357335833593360336133623363336433653366336733683369337033713372337333743375337633773378337933803381338233833384338533863387338833893390339133923393339433953396339733983399340034013402340334043405340634073408340934103411341234133414341534163417341834193420342134223423342434253426342734283429343034313432343334343435343634373438343934403441344234433444344534463447344834493450345134523453345434553456345734583459346034613462346334643465346634673468346934703471347234733474347534763477347834793480348134823483348434853486348734883489349034913492349334943495349634973498349935003501350235033504350535063507350835093510351135123513351435153516351735183519352035213522352335243525352635273528352935303531353235333534353535363537353835393540354135423543354435453546354735483549355035513552355335543555355635573558355935603561356235633564356535663567356835693570357135723573357435753576357735783579358035813582358335843585358635873588358935903591359235933594359535963597359835993600360136023603360436053606360736083609361036113612361336143615361636173618361936203621362236233624362536263627362836293630363136323633363436353636363736383639364036413642364336443645364636473648364936503651365236533654365536563657365836593660366136623663366436653666366736683669367036713672367336743675367636773678367936803681368236833684368536863687368836893690369136923693369436953696369736983699370037013702370337043705370637073708370937103711371237133714371537163717371837193720372137223723372437253726372737283729373037313732373337343735373637373738373937403741374237433744374537463747374837493750375137523753375437553756375737583759376037613762376337643765376637673768376937703771377237733774377537763777377837793780378137823783378437853786378737883789379037913792379337943795379637973798379938003801380238033804380538063807380838093810381138123813381438153816381738183819382038213822382338243825382638273828382938303831383238333834383538363837383838393840384138423843384438453846384738483849385038513852385338543855385638573858385938603861386238633864386538663867386838693870387138723873387438753876387738783879388038813882388338843885388638873888388938903891389238933894389538963897389838993900390139023903390439053906390739083909391039113912391339143915391639173918391939203921392239233924392539263927392839293930393139323933393439353936393739383939394039413942394339443945394639473948394939503951395239533954395539563957395839593960396139623963396439653966396739683969397039713972397339743975397639773978397939803981398239833984398539863987398839893990399139923993399439953996399739983999400040014002400340044005400640074008400940104011401240134014401540164017401840194020402140224023402440254026402740284029403040314032403340344035403640374038403940404041404240434044404540464047404840494050405140524053405440554056405740584059406040614062406340644065406640674068406940704071407240734074407540764077407840794080408140824083408440854086408740884089409040914092409340944095409640974098409941004101410241034104410541064107410841094110411141124113411441154116411741184119412041214122412341244125412641274128412941304131413241334134413541364137413841394140414141424143414441454146414741484149415041514152415341544155415641574158415941604161416241634164416541664167416841694170417141724173417441754176417741784179418041814182418341844185418641874188418941904191419241934194419541964197419841994200420142024203420442054206420742084209421042114212421342144215421642174218421942204221422242234224422542264227422842294230423142324233423442354236423742384239424042414242424342444245424642474248424942504251425242534254425542564257425842594260426142624263426442654266426742684269427042714272427342744275427642774278427942804281428242834284428542864287428842894290429142924293429442954296429742984299430043014302430343044305430643074308430943104311431243134314431543164317431843194320432143224323432443254326432743284329433043314332433343344335433643374338433943404341434243434344434543464347434843494350435143524353435443554356435743584359436043614362436343644365436643674368436943704371437243734374437543764377437843794380438143824383438443854386438743884389439043914392439343944395439643974398439944004401440244034404440544064407440844094410441144124413441444154416441744184419442044214422442344244425442644274428442944304431443244334434443544364437443844394440444144424443444444454446444744484449445044514452445344544455445644574458445944604461446244634464446544664467446844694470447144724473447444754476447744784479448044814482448344844485448644874488448944904491449244934494449544964497449844994500450145024503450445054506450745084509451045114512451345144515451645174518451945204521452245234524452545264527452845294530453145324533453445354536453745384539454045414542454345444545454645474548454945504551455245534554455545564557455845594560456145624563456445654566456745684569457045714572457345744575457645774578457945804581458245834584458545864587458845894590459145924593459445954596459745984599460046014602460346044605460646074608460946104611461246134614461546164617461846194620462146224623462446254626462746284629463046314632463346344635463646374638463946404641464246434644464546464647464846494650465146524653465446554656465746584659466046614662466346644665466646674668466946704671467246734674467546764677467846794680468146824683468446854686468746884689469046914692469346944695469646974698469947004701470247034704470547064707470847094710471147124713471447154716471747184719472047214722472347244725472647274728472947304731473247334734473547364737473847394740474147424743474447454746474747484749475047514752475347544755475647574758475947604761476247634764476547664767476847694770477147724773477447754776477747784779478047814782478347844785478647874788478947904791479247934794479547964797479847994800480148024803480448054806480748084809481048114812481348144815481648174818481948204821482248234824482548264827482848294830483148324833483448354836483748384839484048414842484348444845484648474848484948504851485248534854485548564857485848594860486148624863486448654866486748684869487048714872487348744875487648774878487948804881488248834884488548864887488848894890489148924893489448954896489748984899490049014902490349044905490649074908490949104911491249134914491549164917491849194920492149224923492449254926492749284929493049314932493349344935493649374938493949404941494249434944494549464947494849494950495149524953495449554956495749584959496049614962496349644965496649674968496949704971497249734974497549764977497849794980498149824983498449854986498749884989499049914992499349944995499649974998499950005001500250035004500550065007500850095010501150125013501450155016501750185019502050215022502350245025502650275028502950305031503250335034503550365037503850395040504150425043504450455046504750485049505050515052505350545055505650575058505950605061506250635064506550665067506850695070507150725073507450755076507750785079508050815082508350845085508650875088508950905091509250935094509550965097509850995100510151025103510451055106510751085109511051115112511351145115511651175118511951205121512251235124512551265127512851295130513151325133513451355136513751385139514051415142514351445145514651475148514951505151515251535154515551565157515851595160516151625163516451655166516751685169517051715172517351745175517651775178517951805181518251835184518551865187518851895190519151925193519451955196519751985199520052015202520352045205520652075208520952105211521252135214521552165217521852195220522152225223522452255226522752285229523052315232523352345235523652375238523952405241524252435244524552465247524852495250525152525253525452555256525752585259526052615262526352645265526652675268526952705271527252735274527552765277527852795280528152825283528452855286528752885289529052915292529352945295529652975298529953005301530253035304530553065307530853095310531153125313531453155316531753185319532053215322532353245325532653275328532953305331533253335334533553365337533853395340534153425343534453455346534753485349535053515352535353545355535653575358535953605361536253635364536553665367536853695370537153725373537453755376537753785379538053815382538353845385538653875388538953905391539253935394539553965397539853995400540154025403540454055406540754085409541054115412541354145415541654175418541954205421542254235424542554265427542854295430543154325433543454355436543754385439544054415442544354445445544654475448544954505451545254535454545554565457545854595460546154625463546454655466546754685469547054715472547354745475547654775478547954805481548254835484548554865487548854895490549154925493549454955496549754985499550055015502550355045505550655075508550955105511551255135514551555165517551855195520552155225523552455255526552755285529553055315532553355345535553655375538553955405541554255435544554555465547554855495550555155525553555455555556555755585559556055615562556355645565556655675568556955705571557255735574557555765577557855795580558155825583558455855586558755885589559055915592559355945595559655975598559956005601560256035604560556065607560856095610561156125613561456155616561756185619562056215622562356245625562656275628562956305631563256335634563556365637563856395640564156425643564456455646564756485649565056515652565356545655565656575658565956605661566256635664566556665667566856695670567156725673567456755676567756785679568056815682568356845685568656875688568956905691569256935694569556965697569856995700570157025703570457055706570757085709571057115712571357145715571657175718571957205721572257235724572557265727572857295730573157325733573457355736573757385739574057415742574357445745574657475748574957505751575257535754575557565757575857595760576157625763576457655766576757685769577057715772577357745775577657775778577957805781578257835784578557865787578857895790579157925793579457955796579757985799580058015802580358045805580658075808580958105811581258135814581558165817581858195820582158225823582458255826582758285829583058315832583358345835583658375838583958405841584258435844584558465847584858495850585158525853585458555856585758585859586058615862586358645865586658675868586958705871587258735874587558765877587858795880588158825883588458855886588758885889589058915892589358945895589658975898589959005901590259035904590559065907590859095910591159125913591459155916591759185919592059215922592359245925592659275928592959305931593259335934593559365937593859395940594159425943594459455946594759485949595059515952595359545955595659575958595959605961596259635964596559665967596859695970597159725973597459755976597759785979598059815982598359845985598659875988598959905991599259935994599559965997599859996000600160026003600460056006600760086009601060116012601360146015601660176018601960206021602260236024602560266027602860296030603160326033603460356036603760386039604060416042604360446045604660476048604960506051605260536054605560566057605860596060606160626063606460656066606760686069607060716072607360746075607660776078607960806081608260836084608560866087608860896090609160926093609460956096609760986099610061016102610361046105610661076108610961106111611261136114611561166117611861196120612161226123612461256126612761286129613061316132613361346135613661376138613961406141614261436144614561466147614861496150615161526153615461556156615761586159616061616162616361646165616661676168616961706171617261736174617561766177617861796180618161826183618461856186618761886189619061916192619361946195619661976198619962006201620262036204620562066207620862096210621162126213621462156216621762186219622062216222622362246225622662276228622962306231623262336234623562366237623862396240624162426243624462456246624762486249625062516252625362546255625662576258625962606261626262636264626562666267626862696270627162726273627462756276627762786279628062816282628362846285628662876288628962906291629262936294629562966297629862996300630163026303630463056306630763086309631063116312631363146315631663176318631963206321632263236324632563266327632863296330633163326333633463356336633763386339634063416342634363446345634663476348634963506351635263536354635563566357635863596360636163626363636463656366636763686369637063716372637363746375637663776378637963806381638263836384638563866387638863896390639163926393639463956396639763986399640064016402640364046405640664076408640964106411641264136414641564166417641864196420642164226423642464256426642764286429643064316432643364346435643664376438643964406441644264436444644564466447644864496450645164526453645464556456645764586459646064616462646364646465646664676468646964706471647264736474647564766477647864796480648164826483648464856486648764886489649064916492649364946495649664976498649965006501650265036504650565066507650865096510651165126513651465156516651765186519652065216522652365246525652665276528652965306531653265336534653565366537653865396540654165426543654465456546654765486549655065516552655365546555655665576558655965606561656265636564656565666567656865696570657165726573657465756576657765786579658065816582658365846585658665876588658965906591659265936594659565966597659865996600660166026603660466056606660766086609661066116612661366146615661666176618661966206621662266236624662566266627662866296630663166326633663466356636663766386639664066416642664366446645664666476648664966506651665266536654665566566657665866596660666166626663666466656666666766686669667066716672667366746675667666776678667966806681668266836684668566866687668866896690669166926693669466956696669766986699670067016702670367046705670667076708670967106711671267136714671567166717671867196720672167226723672467256726672767286729673067316732673367346735673667376738673967406741674267436744674567466747674867496750675167526753675467556756675767586759676067616762676367646765676667676768676967706771677267736774677567766777677867796780678167826783678467856786678767886789679067916792679367946795679667976798679968006801680268036804680568066807680868096810681168126813681468156816681768186819682068216822682368246825682668276828682968306831683268336834683568366837683868396840684168426843684468456846684768486849685068516852685368546855685668576858685968606861686268636864686568666867686868696870687168726873687468756876687768786879688068816882688368846885688668876888688968906891689268936894689568966897689868996900690169026903690469056906690769086909691069116912691369146915691669176918691969206921692269236924692569266927692869296930693169326933693469356936693769386939694069416942694369446945694669476948694969506951695269536954695569566957695869596960696169626963696469656966696769686969697069716972697369746975697669776978697969806981698269836984698569866987698869896990699169926993699469956996699769986999700070017002700370047005700670077008700970107011701270137014701570167017701870197020702170227023702470257026702770287029703070317032703370347035703670377038703970407041704270437044704570467047704870497050705170527053705470557056705770587059706070617062706370647065706670677068706970707071707270737074707570767077707870797080708170827083708470857086708770887089709070917092709370947095709670977098709971007101710271037104710571067107710871097110711171127113711471157116711771187119712071217122712371247125712671277128712971307131713271337134713571367137713871397140714171427143714471457146714771487149715071517152715371547155715671577158715971607161716271637164716571667167716871697170717171727173717471757176717771787179718071817182718371847185718671877188718971907191719271937194719571967197719871997200720172027203720472057206720772087209721072117212721372147215721672177218721972207221722272237224722572267227722872297230723172327233723472357236723772387239724072417242724372447245724672477248724972507251725272537254725572567257725872597260726172627263726472657266726772687269727072717272727372747275727672777278727972807281728272837284728572867287728872897290729172927293729472957296729772987299730073017302730373047305730673077308730973107311731273137314731573167317731873197320732173227323732473257326732773287329733073317332733373347335733673377338733973407341734273437344734573467347734873497350735173527353735473557356735773587359736073617362736373647365736673677368736973707371737273737374737573767377737873797380738173827383738473857386738773887389739073917392739373947395739673977398739974007401740274037404740574067407740874097410741174127413741474157416741774187419742074217422742374247425742674277428742974307431743274337434743574367437743874397440744174427443744474457446744774487449745074517452745374547455745674577458745974607461746274637464746574667467746874697470747174727473747474757476747774787479748074817482748374847485748674877488748974907491749274937494749574967497749874997500750175027503750475057506750775087509751075117512751375147515751675177518751975207521752275237524752575267527752875297530753175327533753475357536753775387539754075417542754375447545754675477548754975507551755275537554755575567557755875597560756175627563756475657566756775687569757075717572757375747575757675777578757975807581758275837584758575867587758875897590759175927593759475957596759775987599760076017602760376047605760676077608760976107611761276137614761576167617761876197620762176227623762476257626762776287629763076317632763376347635763676377638763976407641764276437644764576467647764876497650765176527653765476557656765776587659766076617662766376647665766676677668766976707671767276737674767576767677767876797680768176827683768476857686768776887689769076917692769376947695769676977698769977007701770277037704770577067707770877097710771177127713771477157716771777187719772077217722772377247725772677277728772977307731773277337734773577367737773877397740774177427743774477457746774777487749775077517752775377547755775677577758775977607761776277637764776577667767776877697770777177727773777477757776777777787779778077817782778377847785778677877788778977907791779277937794779577967797779877997800780178027803780478057806780778087809781078117812781378147815781678177818781978207821782278237824782578267827782878297830783178327833783478357836783778387839784078417842784378447845784678477848784978507851785278537854785578567857785878597860786178627863786478657866786778687869787078717872787378747875787678777878787978807881788278837884788578867887788878897890789178927893789478957896789778987899790079017902790379047905790679077908790979107911791279137914791579167917791879197920792179227923792479257926792779287929793079317932793379347935793679377938793979407941794279437944794579467947794879497950795179527953795479557956795779587959796079617962796379647965796679677968796979707971797279737974797579767977797879797980798179827983798479857986798779887989799079917992799379947995799679977998799980008001800280038004800580068007800880098010801180128013801480158016801780188019802080218022802380248025802680278028802980308031803280338034803580368037803880398040804180428043804480458046804780488049805080518052805380548055805680578058805980608061806280638064806580668067806880698070807180728073807480758076807780788079808080818082808380848085808680878088808980908091809280938094809580968097809880998100810181028103810481058106810781088109811081118112811381148115811681178118811981208121812281238124812581268127812881298130813181328133813481358136813781388139814081418142814381448145814681478148814981508151815281538154815581568157815881598160816181628163816481658166816781688169817081718172817381748175817681778178817981808181818281838184818581868187818881898190819181928193819481958196819781988199820082018202820382048205820682078208820982108211821282138214821582168217821882198220822182228223822482258226822782288229823082318232823382348235823682378238823982408241824282438244824582468247824882498250825182528253825482558256825782588259826082618262826382648265826682678268826982708271827282738274827582768277827882798280828182828283828482858286828782888289829082918292829382948295829682978298829983008301830283038304830583068307830883098310831183128313831483158316831783188319832083218322832383248325832683278328832983308331833283338334833583368337833883398340834183428343834483458346834783488349835083518352835383548355835683578358835983608361836283638364836583668367836883698370837183728373837483758376837783788379838083818382838383848385838683878388838983908391839283938394839583968397839883998400840184028403840484058406840784088409841084118412841384148415841684178418841984208421842284238424842584268427842884298430843184328433843484358436843784388439844084418442844384448445844684478448844984508451845284538454845584568457845884598460846184628463846484658466846784688469847084718472847384748475847684778478847984808481848284838484848584868487848884898490849184928493849484958496849784988499850085018502850385048505850685078508850985108511851285138514851585168517851885198520852185228523852485258526852785288529853085318532853385348535853685378538853985408541854285438544854585468547854885498550855185528553855485558556855785588559856085618562856385648565856685678568856985708571857285738574857585768577857885798580858185828583858485858586858785888589859085918592859385948595859685978598859986008601860286038604860586068607860886098610861186128613861486158616861786188619862086218622862386248625862686278628862986308631863286338634863586368637863886398640864186428643864486458646864786488649865086518652865386548655865686578658865986608661866286638664866586668667866886698670867186728673867486758676867786788679868086818682868386848685868686878688868986908691869286938694869586968697869886998700870187028703870487058706870787088709871087118712871387148715871687178718871987208721872287238724872587268727872887298730873187328733873487358736873787388739874087418742874387448745874687478748874987508751875287538754875587568757875887598760876187628763876487658766876787688769877087718772877387748775877687778778877987808781878287838784878587868787878887898790879187928793879487958796879787988799880088018802880388048805880688078808880988108811881288138814881588168817881888198820882188228823882488258826882788288829883088318832883388348835883688378838883988408841884288438844884588468847884888498850885188528853885488558856885788588859886088618862886388648865886688678868886988708871887288738874887588768877887888798880888188828883888488858886888788888889889088918892889388948895889688978898889989008901890289038904890589068907890889098910891189128913891489158916891789188919892089218922892389248925892689278928892989308931893289338934893589368937893889398940894189428943894489458946894789488949895089518952895389548955895689578958895989608961896289638964896589668967896889698970897189728973897489758976897789788979898089818982898389848985898689878988898989908991899289938994899589968997899889999000900190029003900490059006900790089009901090119012901390149015901690179018901990209021902290239024902590269027902890299030903190329033903490359036903790389039904090419042904390449045904690479048904990509051905290539054905590569057905890599060906190629063906490659066906790689069907090719072907390749075907690779078907990809081908290839084908590869087908890899090909190929093909490959096909790989099910091019102910391049105910691079108910991109111911291139114911591169117911891199120912191229123912491259126912791289129913091319132913391349135913691379138913991409141914291439144914591469147914891499150915191529153915491559156915791589159916091619162916391649165
  1. unit Compile;
  2. {
  3. Inno Setup
  4. Copyright (C) 1997-2024 Jordan Russell
  5. Portions by Martijn Laan
  6. For conditions of distribution and use, see LICENSE.TXT.
  7. Compiler
  8. }
  9. {x$DEFINE STATICPREPROC}
  10. { For debugging purposes, remove the 'x' to have it link the ISPP code
  11. into this program and not depend on ISPP.dll. Most useful when combined
  12. with CompForm's STATICCOMPILER. }
  13. {$I VERSION.INC}
  14. interface
  15. uses
  16. Windows, SysUtils, CompInt;
  17. function ISCompileScript(const Params: TCompileScriptParamsEx;
  18. const PropagateExceptions: Boolean): Integer;
  19. function ISGetVersion: PCompilerVersionInfo;
  20. type
  21. EISCompileError = class(Exception);
  22. implementation
  23. uses
  24. CompPreprocInt, Commctrl, Consts, Classes, IniFiles, TypInfo, AnsiStrings, Math,
  25. Generics.Collections, WideStrUtils,
  26. PathFunc, CmnFunc2, Struct, Int64Em, CompMsgs, SetupEnt,
  27. FileClass, Compress, CompressZlib, bzlib, LZMA, ArcFour, SHA1,
  28. MsgIDs, SetupSectionDirectives, LangOptionsSectionDirectives, DebugStruct, VerInfo, ResUpdate, CompExeUpdate,
  29. {$IFDEF STATICPREPROC}
  30. IsppPreprocess,
  31. {$ENDIF}
  32. ScriptCompiler, SimpleExpression, SetupTypes;
  33. type
  34. TParamInfo = record
  35. Name: String;
  36. Flags: set of (piRequired, piNoEmpty, piNoQuotes);
  37. end;
  38. TParamValue = record
  39. Found: Boolean;
  40. Data: String;
  41. end;
  42. TEnumIniSectionProc = procedure(const Line: PChar; const Ext: Integer) of object;
  43. TAllowedConst = (acOldData, acBreak);
  44. TAllowedConsts = set of TAllowedConst;
  45. TLineInfo = class
  46. public
  47. FileName: String;
  48. FileLineNumber: Integer;
  49. end;
  50. TPreLangData = class
  51. public
  52. Name: String;
  53. LanguageCodePage: Integer;
  54. end;
  55. TLangData = class
  56. public
  57. MessagesDefined: array[TSetupMessageID] of Boolean;
  58. Messages: array[TSetupMessageID] of String;
  59. end;
  60. TSignTool = class
  61. Name, Command: String;
  62. end;
  63. TNameAndAccessMask = record
  64. Name: String;
  65. Mask: DWORD;
  66. end;
  67. TLowFragList = class(TList)
  68. protected
  69. procedure Grow; override;
  70. end;
  71. TLowFragStringList = class
  72. private
  73. FInternalList: TLowFragList;
  74. function Get(Index: Integer): String;
  75. function GetCount: Integer;
  76. procedure Put(Index: Integer; const Value: String);
  77. public
  78. constructor Create;
  79. destructor Destroy; override;
  80. function Add(const S: String): Integer;
  81. procedure Clear;
  82. property Count: Integer read GetCount;
  83. property Strings[Index: Integer]: String read Get write Put; default;
  84. end;
  85. THashStringItem = record
  86. Hash: Longint;
  87. Str: String;
  88. end;
  89. const
  90. MaxHashStringItemListSize = MaxInt div 16;
  91. type
  92. PHashStringItemList = ^THashStringItemList;
  93. THashStringItemList = array[0..MaxHashStringItemListSize-1] of THashStringItem;
  94. THashStringList = class
  95. private
  96. FCapacity: Integer;
  97. FCount: Integer;
  98. FIgnoreDuplicates: Boolean;
  99. FList: PHashStringItemList;
  100. procedure Grow;
  101. public
  102. destructor Destroy; override;
  103. function Add(const S: String): Integer;
  104. function CaseInsensitiveIndexOf(const S: String): Integer;
  105. procedure Clear;
  106. function Get(Index: Integer): String;
  107. property Count: Integer read FCount;
  108. property IgnoreDuplicates: Boolean read FIgnoreDuplicates write FIgnoreDuplicates;
  109. property Strings[Index: Integer]: String read Get; default;
  110. end;
  111. PScriptFileLine = ^TScriptFileLine;
  112. TScriptFileLine = record
  113. LineFilename: String;
  114. LineNumber: Integer;
  115. LineText: String;
  116. end;
  117. TScriptFileLines = class
  118. private
  119. FLines: TLowFragList;
  120. function Get(Index: Integer): PScriptFileLine;
  121. function GetCount: Integer;
  122. function GetText: String;
  123. public
  124. constructor Create;
  125. destructor Destroy; override;
  126. procedure Add(const LineFilename: String; const LineNumber: Integer;
  127. const LineText: String);
  128. property Count: Integer read GetCount;
  129. property Lines[Index: Integer]: PScriptFileLine read Get; default;
  130. property Text: String read GetText;
  131. end;
  132. TCheckOrInstallKind = (cikCheck, cikDirectiveCheck, cikInstall);
  133. TSetupCompiler = class
  134. private
  135. ScriptFiles: TStringList;
  136. PreprocOptionsString: String;
  137. PreprocCleanupProc: TPreprocCleanupProc;
  138. PreprocCleanupProcData: Pointer;
  139. LanguageEntries,
  140. CustomMessageEntries,
  141. PermissionEntries,
  142. TypeEntries,
  143. ComponentEntries,
  144. TaskEntries,
  145. DirEntries,
  146. FileEntries,
  147. FileLocationEntries,
  148. IconEntries,
  149. IniEntries,
  150. RegistryEntries,
  151. InstallDeleteEntries,
  152. UninstallDeleteEntries,
  153. RunEntries,
  154. UninstallRunEntries: TList;
  155. FileLocationEntryFilenames: THashStringList;
  156. WarningsList: THashStringList;
  157. ExpectedCustomMessageNames: TStringList;
  158. MissingMessagesWarning, MissingRunOnceIdsWarning, MissingRunOnceIds, NotRecognizedMessagesWarning, UsedUserAreasWarning: Boolean;
  159. UsedUserAreas: TStringList;
  160. PreprocIncludedFilenames: TStringList;
  161. PreprocOutput: String;
  162. DefaultLangData: TLangData;
  163. PreLangDataList, LangDataList: TList;
  164. SignToolList: TList;
  165. SignTools, SignToolsParams: TStringList;
  166. SignToolRetryCount, SignToolRetryDelay, SignToolMinimumTimeBetween: Integer;
  167. SignToolRunMinimized: Boolean;
  168. LastSignCommandStartTick: DWORD;
  169. OutputDir, OutputBaseFilename, OutputManifestFile, SignedUninstallerDir,
  170. ExeFilename: String;
  171. Output, FixedOutput, FixedOutputDir, FixedOutputBaseFilename: Boolean;
  172. CompressMethod: TSetupCompressMethod;
  173. InternalCompressLevel, CompressLevel: Integer;
  174. InternalCompressProps, CompressProps: TLZMACompressorProps;
  175. UseSolidCompression: Boolean;
  176. DontMergeDuplicateFiles: Boolean;
  177. CryptKey: String;
  178. TimeStampsInUTC: Boolean;
  179. TimeStampRounding: Integer;
  180. TouchDateOption: (tdCurrent, tdNone, tdExplicit);
  181. TouchDateYear, TouchDateMonth, TouchDateDay: Integer;
  182. TouchTimeOption: (ttCurrent, ttNone, ttExplicit);
  183. TouchTimeHour, TouchTimeMinute, TouchTimeSecond: Integer;
  184. SetupHeader: TSetupHeader;
  185. SetupDirectiveLines: array[TSetupSectionDirective] of Integer;
  186. UseSetupLdr, DiskSpanning, BackSolid, TerminalServicesAware, DEPCompatible, ASLRCompatible: Boolean;
  187. DiskSliceSize, DiskClusterSize, SlicesPerDisk, ReserveBytes: Longint;
  188. LicenseFile, InfoBeforeFile, InfoAfterFile, WizardImageFile: String;
  189. WizardSmallImageFile: String;
  190. DefaultDialogFontName: String;
  191. VersionInfoVersion, VersionInfoProductVersion: TFileVersionNumbers;
  192. VersionInfoVersionOriginalValue, VersionInfoCompany, VersionInfoCopyright,
  193. VersionInfoDescription, VersionInfoTextVersion, VersionInfoProductName, VersionInfoOriginalFileName,
  194. VersionInfoProductTextVersion, VersionInfoProductVersionOriginalValue: String;
  195. SetupIconFilename: String;
  196. CodeText: TStringList;
  197. CodeCompiler: TScriptCompiler;
  198. CompiledCodeText: AnsiString;
  199. CompileWasAlreadyCalled: Boolean;
  200. LineFilename: String;
  201. LineNumber: Integer;
  202. DebugInfo, CodeDebugInfo: TMemoryStream;
  203. DebugEntryCount, VariableDebugEntryCount: Integer;
  204. CompiledCodeTextLength, CompiledCodeDebugInfoLength: Integer;
  205. GotPrevFilename: Boolean;
  206. PrevFilename: String;
  207. PrevFileIndex: Integer;
  208. TotalBytesToCompress, BytesCompressedSoFar: Integer64;
  209. CompressionInProgress: Boolean;
  210. CompressionStartTick: DWORD;
  211. CachedUserDocsDir: String;
  212. procedure AddStatus(const S: String; const Warning: Boolean = False);
  213. procedure AddStatusFmt(const Msg: String; const Args: array of const;
  214. const Warning: Boolean);
  215. procedure AbortCompile(const Msg: String);
  216. procedure AbortCompileFmt(const Msg: String; const Args: array of const);
  217. procedure AbortCompileOnLine(const Msg: String);
  218. procedure AbortCompileOnLineFmt(const Msg: String;
  219. const Args: array of const);
  220. procedure AbortCompileParamError(const Msg, ParamName: String);
  221. function PrependDirName(const Filename, Dir: String): String;
  222. function PrependSourceDirName(const Filename: String): String;
  223. procedure CallIdleProc;
  224. procedure DoCallback(const Code: Integer; var Data: TCompilerCallbackData);
  225. procedure EnumIniSection(const EnumProc: TEnumIniSectionProc;
  226. const SectionName: String; const Ext: Integer; const Verbose, SkipBlankLines: Boolean;
  227. const Filename: String; const LangSection: Boolean = False; const LangSectionPre: Boolean = False);
  228. function EvalCheckOrInstallIdentifier(Sender: TSimpleExpression; const Name: String;
  229. const Parameters: array of const): Boolean;
  230. procedure CheckCheckOrInstall(const ParamName, ParamData: String;
  231. const Kind: TCheckOrInstallKind);
  232. function CheckConst(const S: String; const MinVersion: TSetupVersionData;
  233. const AllowedConsts: TAllowedConsts): Boolean;
  234. procedure CheckCustomMessageDefinitions;
  235. procedure CheckCustomMessageReferences;
  236. procedure EnumTypesProc(const Line: PChar; const Ext: Integer);
  237. procedure EnumComponentsProc(const Line: PChar; const Ext: Integer);
  238. procedure EnumTasksProc(const Line: PChar; const Ext: Integer);
  239. procedure EnumDirsProc(const Line: PChar; const Ext: Integer);
  240. procedure EnumIconsProc(const Line: PChar; const Ext: Integer);
  241. procedure EnumINIProc(const Line: PChar; const Ext: Integer);
  242. procedure EnumLangOptionsPreProc(const Line: PChar; const Ext: Integer);
  243. procedure EnumLangOptionsProc(const Line: PChar; const Ext: Integer);
  244. procedure EnumLanguagesPreProc(const Line: PChar; const Ext: Integer);
  245. procedure EnumLanguagesProc(const Line: PChar; const Ext: Integer);
  246. procedure EnumRegistryProc(const Line: PChar; const Ext: Integer);
  247. procedure EnumDeleteProc(const Line: PChar; const Ext: Integer);
  248. procedure EnumFilesProc(const Line: PChar; const Ext: Integer);
  249. procedure EnumRunProc(const Line: PChar; const Ext: Integer);
  250. procedure EnumSetupProc(const Line: PChar; const Ext: Integer);
  251. procedure EnumMessagesProc(const Line: PChar; const Ext: Integer);
  252. procedure EnumCustomMessagesProc(const Line: PChar; const Ext: Integer);
  253. procedure ExtractParameters(S: PChar; const ParamInfo: array of TParamInfo;
  254. var ParamValues: array of TParamValue);
  255. function FindLangEntryIndexByName(const AName: String; const Pre: Boolean): Integer;
  256. function FindSignToolIndexByName(const AName: String): Integer;
  257. function GetLZMAExeFilename(const Allow64Bit: Boolean): String;
  258. procedure InitBzipDLL;
  259. procedure InitCryptDLL;
  260. procedure InitPreLangData(const APreLangData: TPreLangData);
  261. procedure InitLanguageEntry(var ALanguageEntry: TSetupLanguageEntry);
  262. procedure InitLZMADLL;
  263. procedure InitPreprocessor;
  264. procedure InitZipDLL;
  265. procedure PopulateLanguageEntryData;
  266. procedure ProcessMinVersionParameter(const ParamValue: TParamValue;
  267. var AMinVersion: TSetupVersionData);
  268. procedure ProcessOnlyBelowVersionParameter(const ParamValue: TParamValue;
  269. var AOnlyBelowVersion: TSetupVersionData);
  270. procedure ProcessPermissionsParameter(ParamData: String;
  271. const AccessMasks: array of TNameAndAccessMask; var PermissionsEntry: Smallint);
  272. function EvalComponentIdentifier(Sender: TSimpleExpression; const Name: String;
  273. const Parameters: array of const): Boolean;
  274. function EvalTaskIdentifier(Sender: TSimpleExpression; const Name: String;
  275. const Parameters: array of const): Boolean;
  276. function EvalLanguageIdentifier(Sender: TSimpleExpression; const Name: String;
  277. const Parameters: array of const): Boolean;
  278. procedure ProcessExpressionParameter(const ParamName,
  279. ParamData: String; OnEvalIdentifier: TSimpleExpressionOnEvalIdentifier;
  280. SlashConvert: Boolean; var ProcessedParamData: String);
  281. procedure ProcessWildcardsParameter(const ParamData: String;
  282. const AWildcards: TStringList; const TooLongMsg: String);
  283. procedure ReadDefaultMessages;
  284. procedure ReadMessagesFromFilesPre(const AFiles: String; const ALangIndex: Integer);
  285. procedure ReadMessagesFromFiles(const AFiles: String; const ALangIndex: Integer);
  286. procedure ReadMessagesFromScriptPre;
  287. procedure ReadMessagesFromScript;
  288. function ReadScriptFile(const Filename: String; const UseCache: Boolean;
  289. const AnsiConvertCodePage: Cardinal): TScriptFileLines;
  290. procedure RenamedConstantCallback(const Cnst, CnstRenamed: String);
  291. procedure EnumCodeProc(const Line: PChar; const Ext: Integer);
  292. procedure ReadCode;
  293. procedure CodeCompilerOnLineToLineInfo(const Line: LongInt; var Filename: String; var FileLine: LongInt);
  294. procedure CodeCompilerOnUsedLine(const Filename: String; const Line, Position: LongInt; const IsProcExit: Boolean);
  295. procedure CodeCompilerOnUsedVariable(const Filename: String; const Line, Col, Param1, Param2, Param3: LongInt; const Param4: AnsiString);
  296. procedure CodeCompilerOnError(const Msg: String; const ErrorFilename: String; const ErrorLine: LongInt);
  297. procedure CodeCompilerOnWarning(const Msg: String);
  298. procedure CompileCode;
  299. function FilenameToFileIndex(const AFileName: String): Integer;
  300. procedure ReadTextFile(const Filename: String; const LangIndex: Integer; var Text: AnsiString);
  301. procedure SeparateDirective(const Line: PChar; var Key, Value: String);
  302. procedure ShiftDebugEntryIndexes(AKind: TDebugEntryKind);
  303. procedure Sign(AExeFilename: String);
  304. procedure SignCommand(const AName, ACommand, AParams, AExeFilename: String; const RetryCount, RetryDelay, MinimumTimeBetween: Integer; const RunMinimized: Boolean);
  305. procedure WriteDebugEntry(Kind: TDebugEntryKind; Index: Integer; StepOutMarker: Boolean = False);
  306. procedure WriteCompiledCodeText(const CompiledCodeText: Ansistring);
  307. procedure WriteCompiledCodeDebugInfo(const CompiledCodeDebugInfo: AnsiString);
  308. function CreateMemoryStreamsFromFiles(const ADirectiveName, AFiles: String): TObjectList<TCustomMemoryStream>;
  309. function CreateMemoryStreamsFromResources(const AResourceNamesPrefixes, AResourceNamesPostfixes: array of String): TObjectList<TCustomMemoryStream>;
  310. public
  311. AppData: Longint;
  312. CallbackProc: TCompilerCallbackProc;
  313. CompilerDir, SourceDir, OriginalSourceDir: String;
  314. constructor Create(AOwner: TComponent);
  315. destructor Destroy; override;
  316. procedure AddSignTool(const Name, Command: String);
  317. procedure Compile;
  318. end;
  319. var
  320. ZipInitialized, BzipInitialized, LZMAInitialized, CryptInitialized: Boolean;
  321. PreprocessorInitialized: Boolean;
  322. PreprocessScriptProc: TPreprocessScriptProc;
  323. const
  324. ParamCommonFlags = 'Flags';
  325. ParamCommonComponents = 'Components';
  326. ParamCommonTasks = 'Tasks';
  327. ParamCommonLanguages = 'Languages';
  328. ParamCommonCheck = 'Check';
  329. ParamCommonBeforeInstall = 'BeforeInstall';
  330. ParamCommonAfterInstall = 'AfterInstall';
  331. ParamCommonMinVersion = 'MinVersion';
  332. ParamCommonOnlyBelowVersion = 'OnlyBelowVersion';
  333. DefaultTypeEntryNames: array[0..2] of PChar = ('full', 'compact', 'custom');
  334. MaxDiskSliceSize = 2100000000;
  335. type
  336. TColor = $7FFFFFFF-1..$7FFFFFFF;
  337. const
  338. clScrollBar = TColor(COLOR_SCROLLBAR or $80000000);
  339. clBackground = TColor(COLOR_BACKGROUND or $80000000);
  340. clActiveCaption = TColor(COLOR_ACTIVECAPTION or $80000000);
  341. clInactiveCaption = TColor(COLOR_INACTIVECAPTION or $80000000);
  342. clMenu = TColor(COLOR_MENU or $80000000);
  343. clWindow = TColor(COLOR_WINDOW or $80000000);
  344. clWindowFrame = TColor(COLOR_WINDOWFRAME or $80000000);
  345. clMenuText = TColor(COLOR_MENUTEXT or $80000000);
  346. clWindowText = TColor(COLOR_WINDOWTEXT or $80000000);
  347. clCaptionText = TColor(COLOR_CAPTIONTEXT or $80000000);
  348. clActiveBorder = TColor(COLOR_ACTIVEBORDER or $80000000);
  349. clInactiveBorder = TColor(COLOR_INACTIVEBORDER or $80000000);
  350. clAppWorkSpace = TColor(COLOR_APPWORKSPACE or $80000000);
  351. clHighlight = TColor(COLOR_HIGHLIGHT or $80000000);
  352. clHighlightText = TColor(COLOR_HIGHLIGHTTEXT or $80000000);
  353. clBtnFace = TColor(COLOR_BTNFACE or $80000000);
  354. clBtnShadow = TColor(COLOR_BTNSHADOW or $80000000);
  355. clGrayText = TColor(COLOR_GRAYTEXT or $80000000);
  356. clBtnText = TColor(COLOR_BTNTEXT or $80000000);
  357. clInactiveCaptionText = TColor(COLOR_INACTIVECAPTIONTEXT or $80000000);
  358. clBtnHighlight = TColor(COLOR_BTNHIGHLIGHT or $80000000);
  359. cl3DDkShadow = TColor(COLOR_3DDKSHADOW or $80000000);
  360. cl3DLight = TColor(COLOR_3DLIGHT or $80000000);
  361. clInfoText = TColor(COLOR_INFOTEXT or $80000000);
  362. clInfoBk = TColor(COLOR_INFOBK or $80000000);
  363. clBlack = TColor($000000);
  364. clMaroon = TColor($000080);
  365. clGreen = TColor($008000);
  366. clOlive = TColor($008080);
  367. clNavy = TColor($800000);
  368. clPurple = TColor($800080);
  369. clTeal = TColor($808000);
  370. clGray = TColor($808080);
  371. clSilver = TColor($C0C0C0);
  372. clRed = TColor($0000FF);
  373. clLime = TColor($00FF00);
  374. clYellow = TColor($00FFFF);
  375. clBlue = TColor($FF0000);
  376. clFuchsia = TColor($FF00FF);
  377. clAqua = TColor($FFFF00);
  378. clLtGray = TColor($C0C0C0);
  379. clDkGray = TColor($808080);
  380. clWhite = TColor($FFFFFF);
  381. clNone = TColor($1FFFFFFF);
  382. clDefault = TColor($20000000);
  383. type
  384. TColorEntry = record
  385. Value: TColor;
  386. Name: string;
  387. end;
  388. const
  389. Colors: array[0..41] of TColorEntry = (
  390. (Value: clBlack; Name: 'clBlack'),
  391. (Value: clMaroon; Name: 'clMaroon'),
  392. (Value: clGreen; Name: 'clGreen'),
  393. (Value: clOlive; Name: 'clOlive'),
  394. (Value: clNavy; Name: 'clNavy'),
  395. (Value: clPurple; Name: 'clPurple'),
  396. (Value: clTeal; Name: 'clTeal'),
  397. (Value: clGray; Name: 'clGray'),
  398. (Value: clSilver; Name: 'clSilver'),
  399. (Value: clRed; Name: 'clRed'),
  400. (Value: clLime; Name: 'clLime'),
  401. (Value: clYellow; Name: 'clYellow'),
  402. (Value: clBlue; Name: 'clBlue'),
  403. (Value: clFuchsia; Name: 'clFuchsia'),
  404. (Value: clAqua; Name: 'clAqua'),
  405. (Value: clWhite; Name: 'clWhite'),
  406. (Value: clScrollBar; Name: 'clScrollBar'),
  407. (Value: clBackground; Name: 'clBackground'),
  408. (Value: clActiveCaption; Name: 'clActiveCaption'),
  409. (Value: clInactiveCaption; Name: 'clInactiveCaption'),
  410. (Value: clMenu; Name: 'clMenu'),
  411. (Value: clWindow; Name: 'clWindow'),
  412. (Value: clWindowFrame; Name: 'clWindowFrame'),
  413. (Value: clMenuText; Name: 'clMenuText'),
  414. (Value: clWindowText; Name: 'clWindowText'),
  415. (Value: clCaptionText; Name: 'clCaptionText'),
  416. (Value: clActiveBorder; Name: 'clActiveBorder'),
  417. (Value: clInactiveBorder; Name: 'clInactiveBorder'),
  418. (Value: clAppWorkSpace; Name: 'clAppWorkSpace'),
  419. (Value: clHighlight; Name: 'clHighlight'),
  420. (Value: clHighlightText; Name: 'clHighlightText'),
  421. (Value: clBtnFace; Name: 'clBtnFace'),
  422. (Value: clBtnShadow; Name: 'clBtnShadow'),
  423. (Value: clGrayText; Name: 'clGrayText'),
  424. (Value: clBtnText; Name: 'clBtnText'),
  425. (Value: clInactiveCaptionText; Name: 'clInactiveCaptionText'),
  426. (Value: clBtnHighlight; Name: 'clBtnHighlight'),
  427. (Value: cl3DDkShadow; Name: 'cl3DDkShadow'),
  428. (Value: cl3DLight; Name: 'cl3DLight'),
  429. (Value: clInfoText; Name: 'clInfoText'),
  430. (Value: clInfoBk; Name: 'clInfoBk'),
  431. (Value: clNone; Name: 'clNone'));
  432. function IdentToColor(const Ident: string; var Color: Longint): Boolean;
  433. var
  434. I: Integer;
  435. begin
  436. for I := Low(Colors) to High(Colors) do
  437. if CompareText(Colors[I].Name, Ident) = 0 then
  438. begin
  439. Result := True;
  440. Color := Longint(Colors[I].Value);
  441. Exit;
  442. end;
  443. Result := False;
  444. end;
  445. function StringToColor(const S: string): TColor;
  446. begin
  447. if not IdentToColor(S, Longint(Result)) then
  448. Result := TColor(StrToInt(S));
  449. end;
  450. function IsRelativePath(const Filename: String): Boolean;
  451. var
  452. L: Integer;
  453. begin
  454. Result := True;
  455. L := Length(Filename);
  456. if ((L >= 1) and (Filename[1] = '\')) or
  457. ((L >= 2) and CharInSet(Filename[1], ['A'..'Z', 'a'..'z']) and (Filename[2] = ':')) then
  458. Result := False;
  459. end;
  460. function GetSelfFilename: String;
  461. { Returns Filename of the calling DLL or application. (ParamStr(0) can only
  462. return the filename of the calling application.) }
  463. var
  464. Buf: array[0..MAX_PATH-1] of Char;
  465. begin
  466. SetString(Result, Buf, GetModuleFileName(HInstance, Buf, SizeOf(Buf)))
  467. end;
  468. function CreateMemoryStreamFromFile(const Filename: String): TMemoryStream;
  469. { Creates a TMemoryStream and loads the contents of the specified file into it }
  470. var
  471. F: TFile;
  472. SizeOfFile: Cardinal;
  473. begin
  474. Result := TMemoryStream.Create;
  475. try
  476. { Why not use TMemoryStream.LoadFromFile here?
  477. 1. On Delphi 2 it opens files for exclusive access (not good).
  478. 2. It doesn't give specific error messages. }
  479. F := TFile.Create(Filename, fdOpenExisting, faRead, fsRead);
  480. try
  481. SizeOfFile := F.CappedSize;
  482. Result.SetSize(SizeOfFile);
  483. F.ReadBuffer(Result.Memory^, SizeOfFile);
  484. finally
  485. F.Free;
  486. end;
  487. except
  488. Result.Free;
  489. raise Exception.CreateFmt(SCompilerReadError, [Filename, GetExceptMessage]);
  490. end;
  491. end;
  492. function ExtractStr(var S: String; const Separator: Char): String;
  493. var
  494. I: Integer;
  495. begin
  496. repeat
  497. I := PathPos(Separator, S);
  498. if I = 0 then I := Length(S)+1;
  499. Result := Trim(Copy(S, 1, I-1));
  500. S := Trim(Copy(S, I+1, Maxint));
  501. until (Result <> '') or (S = '');
  502. end;
  503. function TSetupCompiler.CreateMemoryStreamsFromFiles(const ADirectiveName, AFiles: String): TObjectList<TCustomMemoryStream>;
  504. procedure AddFile(const Filename: String);
  505. begin
  506. AddStatus(Format(SCompilerStatusReadingInFile, [FileName]));
  507. Result.Add(CreateMemoryStreamFromFile(FileName));
  508. end;
  509. var
  510. Filename, SearchSubDir: String;
  511. AFilesList: TStringList;
  512. I: Integer;
  513. H: THandle;
  514. FindData: TWin32FindData;
  515. begin
  516. Result := TObjectList<TCustomMemoryStream>.Create;
  517. try
  518. { In older versions only one file could be listed and comma's could be used so
  519. before treating AFiles as a list, first check if it's actually a single file
  520. with a comma in its name. }
  521. Filename := PrependSourceDirName(AFiles);
  522. if NewFileExists(Filename) then
  523. AddFile(Filename)
  524. else begin
  525. AFilesList := TStringList.Create;
  526. try
  527. ProcessWildcardsParameter(AFiles, AFilesList,
  528. Format(SCompilerDirectivePatternTooLong, [ADirectiveName]));
  529. for I := 0 to AFilesList.Count-1 do begin
  530. Filename := PrependSourceDirName(AFilesList[I]);
  531. if IsWildcard(FileName) then begin
  532. H := FindFirstFile(PChar(Filename), FindData);
  533. if H <> INVALID_HANDLE_VALUE then begin
  534. try
  535. SearchSubDir := PathExtractPath(Filename);
  536. repeat
  537. if FindData.dwFileAttributes and (FILE_ATTRIBUTE_DIRECTORY or FILE_ATTRIBUTE_HIDDEN) <> 0 then
  538. Continue;
  539. AddFile(SearchSubDir + FindData.cFilename);
  540. until not FindNextFile(H, FindData);
  541. finally
  542. Windows.FindClose(H);
  543. end;
  544. end;
  545. end else
  546. AddFile(Filename); { use the case specified in the script }
  547. end;
  548. finally
  549. AFilesList.Free;
  550. end;
  551. end;
  552. except
  553. Result.Free;
  554. raise;
  555. end;
  556. end;
  557. function TSetupCompiler.CreateMemoryStreamsFromResources(const AResourceNamesPrefixes, AResourceNamesPostfixes: array of String): TObjectList<TCustomMemoryStream>;
  558. var
  559. I, J: Integer;
  560. begin
  561. Result := TObjectList<TCustomMemoryStream>.Create;
  562. try
  563. for I := 0 to Length(AResourceNamesPrefixes)-1 do
  564. for J := 0 to Length(AResourceNamesPostfixes)-1 do
  565. Result.Add(TResourceStream.Create(HInstance, AResourceNamesPrefixes[I]+AResourceNamesPostfixes[J], RT_RCDATA));
  566. except
  567. Result.Free;
  568. raise;
  569. end;
  570. end;
  571. function FileSizeAndCRCIs(const Filename: String; const Size: Cardinal;
  572. const CRC: Longint): Boolean;
  573. var
  574. F: TFile;
  575. SizeOfFile: Integer64;
  576. Buf: AnsiString;
  577. begin
  578. Result := False;
  579. try
  580. F := TFile.Create(Filename, fdOpenExisting, faRead, fsRead);
  581. try
  582. SizeOfFile := F.Size;
  583. if (SizeOfFile.Lo = Size) and (SizeOfFile.Hi = 0) then begin
  584. SetLength(Buf, Size);
  585. F.ReadBuffer(Buf[1], Size);
  586. if GetCRC32(Buf[1], Size) = CRC then
  587. Result := True;
  588. end;
  589. finally
  590. F.Free;
  591. end;
  592. except
  593. end;
  594. end;
  595. const
  596. IMAGE_NT_SIGNATURE = $00004550; { 'PE'#0#0 }
  597. IMAGE_NT_OPTIONAL_HDR32_MAGIC = $10b;
  598. type
  599. TImageFileHeader = packed record
  600. Machine: Word;
  601. NumberOfSections: Word;
  602. TimeDateStamp: DWORD;
  603. PointerToSymbolTable: DWORD;
  604. NumberOfSymbols: DWORD;
  605. SizeOfOptionalHeader: Word;
  606. Characteristics: Word;
  607. end;
  608. function IsX86OrX64Executable(const F: TFile): Boolean;
  609. const
  610. IMAGE_FILE_MACHINE_I386 = $014C;
  611. IMAGE_FILE_MACHINE_AMD64 = $8664;
  612. var
  613. DosHeader: array[0..63] of Byte;
  614. PEHeaderOffset: Longint;
  615. PESigAndHeader: packed record
  616. Sig: DWORD;
  617. Machine: Word;
  618. end;
  619. begin
  620. Result := False;
  621. if F.Read(DosHeader, SizeOf(DosHeader)) = SizeOf(DosHeader) then begin
  622. if (DosHeader[0] = Ord('M')) and (DosHeader[1] = Ord('Z')) then begin
  623. PEHeaderOffset := PLongint(@DosHeader[60])^;
  624. if PEHeaderOffset > 0 then begin
  625. F.Seek(PEHeaderOffset);
  626. if F.Read(PESigAndHeader, SizeOf(PESigAndHeader)) = SizeOf(PESigAndHeader) then begin
  627. if (PESigAndHeader.Sig = IMAGE_NT_SIGNATURE) and
  628. ((PESigAndHeader.Machine = IMAGE_FILE_MACHINE_I386) or
  629. (PESigAndHeader.Machine = IMAGE_FILE_MACHINE_AMD64)) then
  630. Result := True;
  631. end;
  632. end;
  633. end;
  634. end;
  635. F.Seek(0);
  636. end;
  637. function CountChars(const S: String; C: Char): Integer;
  638. var
  639. I: Integer;
  640. begin
  641. Result := 0;
  642. for I := 1 to Length(S) do
  643. if S[I] = C then
  644. Inc(Result);
  645. end;
  646. function IsValidIdentString(const S: String; AllowBackslash, AllowOperators: Boolean): Boolean;
  647. var
  648. I, N: Integer;
  649. begin
  650. if S = '' then
  651. Result := False
  652. else if not AllowOperators and ((CompareText(S, 'not') = 0) or
  653. (CompareText(S, 'and') = 0) or (CompareText(S, 'or') = 0)) then
  654. Result := False
  655. else begin
  656. N := Length(S);
  657. for I := 1 to N do
  658. if not (CharInSet(S[I], ['A'..'Z', 'a'..'z', '_']) or
  659. ((I > 1) and CharInSet(S[I], ['0'..'9'])) or
  660. (AllowBackslash and (I > 1) and (I < N) and (S[I] = '\'))) then begin
  661. Result := False;
  662. Exit;
  663. end;
  664. Result := True;
  665. end;
  666. end;
  667. procedure SkipWhitespace(var S: PChar);
  668. begin
  669. while CharInSet(S^, [#1..' ']) do
  670. Inc(S);
  671. end;
  672. function ExtractWords(var S: PChar; const Sep: Char): String;
  673. { Extracts characters from S until it reaches the character Sep or the end
  674. of S. The returned string has trailing whitespace characters trimmed off. }
  675. var
  676. StartPos, EndPos: PChar;
  677. begin
  678. StartPos := S;
  679. EndPos := S;
  680. while (S^ <> #0) and (S^ <> Sep) do begin
  681. if S^ > ' ' then
  682. EndPos := S + 1;
  683. Inc(S);
  684. end;
  685. SetString(Result, StartPos, EndPos - StartPos);
  686. end;
  687. function UnescapeBraces(const S: String): String;
  688. { Changes all '{{' to '{'. Assumes that S does not contain any constants; you
  689. should check before calling. }
  690. var
  691. I: Integer;
  692. begin
  693. Result := S;
  694. I := 1;
  695. while I < Length(Result) do begin
  696. if Result[I] = '{' then begin
  697. Inc(I);
  698. if Result[I] = '{' then
  699. Delete(Result, I, 1);
  700. end
  701. else
  702. Inc(I);
  703. end;
  704. end;
  705. type
  706. HCRYPTPROV = DWORD;
  707. const
  708. PROV_RSA_FULL = 1;
  709. CRYPT_VERIFYCONTEXT = $F0000000;
  710. function CryptAcquireContext(var phProv: HCRYPTPROV; pszContainer: PAnsiChar;
  711. pszProvider: PAnsiChar; dwProvType: DWORD; dwFlags: DWORD): BOOL;
  712. stdcall; external advapi32 name 'CryptAcquireContextA';
  713. function CryptReleaseContext(hProv: HCRYPTPROV; dwFlags: DWORD): BOOL;
  714. stdcall; external advapi32 name 'CryptReleaseContext';
  715. function CryptGenRandom(hProv: HCRYPTPROV; dwLen: DWORD; pbBuffer: Pointer): BOOL;
  716. stdcall; external advapi32 name 'CryptGenRandom';
  717. var
  718. CryptProv: HCRYPTPROV;
  719. procedure GenerateRandomBytes(var Buffer; Bytes: Cardinal);
  720. var
  721. ErrorCode: DWORD;
  722. begin
  723. if CryptProv = 0 then begin
  724. if not CryptAcquireContext(CryptProv, nil, nil, PROV_RSA_FULL,
  725. CRYPT_VERIFYCONTEXT) then begin
  726. ErrorCode := GetLastError;
  727. raise Exception.CreateFmt(SCompilerFunctionFailedWithCode,
  728. ['CryptAcquireContext', ErrorCode, Win32ErrorString(ErrorCode)]);
  729. end;
  730. { Note: CryptProv is released in the 'finalization' section of this unit }
  731. end;
  732. FillChar(Buffer, Bytes, 0);
  733. if not CryptGenRandom(CryptProv, Bytes, @Buffer) then begin
  734. ErrorCode := GetLastError;
  735. raise Exception.CreateFmt(SCompilerFunctionFailedWithCode,
  736. ['CryptGenRandom', ErrorCode, Win32ErrorString(ErrorCode)]);
  737. end;
  738. end;
  739. { TLowFragList }
  740. procedure TLowFragList.Grow;
  741. var
  742. Delta: Integer;
  743. begin
  744. { Delphi 2's TList.Grow induces memory fragmentation big time. This is the
  745. Grow code from Delphi 3 and later. }
  746. if Capacity > 64 then Delta := Capacity div 4 else
  747. if Capacity > 8 then Delta := 16 else
  748. Delta := 4;
  749. SetCapacity(Capacity + Delta);
  750. end;
  751. { TLowFragStringList }
  752. constructor TLowFragStringList.Create;
  753. begin
  754. inherited;
  755. FInternalList := TLowFragList.Create;
  756. end;
  757. destructor TLowFragStringList.Destroy;
  758. begin
  759. if Assigned(FInternalList) then begin
  760. Clear;
  761. FInternalList.Free;
  762. end;
  763. inherited;
  764. end;
  765. function TLowFragStringList.Add(const S: String): Integer;
  766. var
  767. P: Pointer;
  768. begin
  769. FInternalList.Expand;
  770. P := nil;
  771. String(P) := S; { bump the ref count }
  772. Result := FInternalList.Add(P);
  773. end;
  774. procedure TLowFragStringList.Clear;
  775. begin
  776. if FInternalList.Count <> 0 then
  777. Finalize(String(FInternalList.List[0]), FInternalList.Count);
  778. FInternalList.Clear;
  779. end;
  780. function TLowFragStringList.Get(Index: Integer): String;
  781. begin
  782. Result := String(FInternalList[Index]);
  783. end;
  784. function TLowFragStringList.GetCount: Integer;
  785. begin
  786. Result := FInternalList.Count;
  787. end;
  788. procedure TLowFragStringList.Put(Index: Integer; const Value: String);
  789. begin
  790. if (Index < 0) or (Index >= FInternalList.Count) then
  791. raise EListError.CreateFmt('List index out of bounds (%d)', [Index]);
  792. String(FInternalList.List[Index]) := Value;
  793. end;
  794. { THashStringList }
  795. destructor THashStringList.Destroy;
  796. begin
  797. Clear;
  798. inherited;
  799. end;
  800. function THashStringList.Add(const S: String): Integer;
  801. var
  802. LS: String;
  803. begin
  804. if FIgnoreDuplicates and (CaseInsensitiveIndexOf(S) <> -1) then begin
  805. Result := -1;
  806. Exit;
  807. end;
  808. Result := FCount;
  809. if Result = FCapacity then
  810. Grow;
  811. LS := PathLowercase(S);
  812. Pointer(FList[Result].Str) := nil; { since Grow doesn't zero init }
  813. FList[Result].Str := S;
  814. FList[Result].Hash := GetCRC32(Pointer(LS)^, Length(LS)*SizeOf(LS[1]));
  815. Inc(FCount);
  816. end;
  817. procedure THashStringList.Clear;
  818. begin
  819. if FCount > 0 then
  820. Finalize(FList[0], FCount);
  821. FCount := 0;
  822. FCapacity := 0;
  823. ReallocMem(FList, 0);
  824. end;
  825. function THashStringList.Get(Index: Integer): String;
  826. begin
  827. if (Index < 0) or (Index >= FCount) then
  828. raise EStringListError.CreateFmt('THashStringList: Index %d is out of bounds',
  829. [Index]);
  830. Result := FList[Index].Str;
  831. end;
  832. procedure THashStringList.Grow;
  833. var
  834. Delta, NewCapacity: Integer;
  835. begin
  836. if FCapacity > 64 then Delta := FCapacity div 4 else
  837. if FCapacity > 8 then Delta := 16 else
  838. Delta := 4;
  839. NewCapacity := FCapacity + Delta;
  840. if NewCapacity > MaxHashStringItemListSize then
  841. raise EStringListError.Create('THashStringList: Exceeded maximum list size');
  842. ReallocMem(FList, NewCapacity * SizeOf(FList[0]));
  843. FCapacity := NewCapacity;
  844. end;
  845. function THashStringList.CaseInsensitiveIndexOf(const S: String): Integer;
  846. var
  847. LS: String;
  848. Hash: Longint;
  849. I: Integer;
  850. begin
  851. LS := PathLowercase(S);
  852. Hash := GetCRC32(Pointer(LS)^, Length(LS)*SizeOf(LS[1]));
  853. for I := 0 to FCount-1 do
  854. if (FList[I].Hash = Hash) and (PathLowercase(FList[I].Str) = LS) then begin
  855. Result := I;
  856. Exit;
  857. end;
  858. Result := -1;
  859. end;
  860. { TScriptFileLines }
  861. constructor TScriptFileLines.Create;
  862. begin
  863. inherited;
  864. FLines := TLowFragList.Create;
  865. end;
  866. destructor TScriptFileLines.Destroy;
  867. var
  868. I: Integer;
  869. begin
  870. if Assigned(FLines) then begin
  871. for I := FLines.Count-1 downto 0 do
  872. Dispose(PScriptFileLine(FLines[I]));
  873. FLines.Free;
  874. end;
  875. inherited;
  876. end;
  877. procedure TScriptFileLines.Add(const LineFilename: String;
  878. const LineNumber: Integer; const LineText: String);
  879. var
  880. L, PrevLine: PScriptFileLine;
  881. begin
  882. FLines.Expand;
  883. New(L);
  884. try
  885. { Memory usage optimization: If LineFilename is equal to the previous
  886. line's LineFilename, then make this line's LineFilename reference the
  887. same string (i.e. just increment its refcount). }
  888. PrevLine := nil;
  889. if (LineFilename <> '') and (FLines.Count > 0) then
  890. PrevLine := PScriptFileLine(FLines[FLines.Count-1]);
  891. if Assigned(PrevLine) and (PrevLine.LineFilename = LineFilename) then
  892. L.LineFilename := PrevLine.LineFilename
  893. else
  894. L.LineFilename := LineFilename;
  895. L.LineNumber := LineNumber;
  896. L.LineText := LineText;
  897. except
  898. Dispose(L);
  899. raise;
  900. end;
  901. FLines.Add(L);
  902. end;
  903. function TScriptFileLines.Get(Index: Integer): PScriptFileLine;
  904. begin
  905. Result := PScriptFileLine(FLines[Index]);
  906. end;
  907. function TScriptFileLines.GetCount: Integer;
  908. begin
  909. Result := FLines.Count;
  910. end;
  911. function TScriptFileLines.GetText: String;
  912. var
  913. I, L, Size, Count: Integer;
  914. P: PChar;
  915. S, LB: string;
  916. begin
  917. Count := GetCount;
  918. Size := 0;
  919. LB := sLineBreak;
  920. for I := 0 to Count-1 do
  921. Inc(Size, Length(Get(I).LineText) + Length(LB));
  922. Dec(Size, Length(LB));
  923. SetString(Result, nil, Size);
  924. P := Pointer(Result);
  925. for I := 0 to Count-1 do begin
  926. S := Get(I).LineText;
  927. L := Length(S);
  928. if L <> 0 then begin
  929. System.Move(Pointer(S)^, P^, L * SizeOf(Char));
  930. Inc(P, L);
  931. end;
  932. if I < Count-1 then begin
  933. L := Length(LB);
  934. if L <> 0 then begin
  935. System.Move(Pointer(LB)^, P^, L * SizeOf(Char));
  936. Inc(P, L);
  937. end;
  938. end;
  939. end;
  940. end;
  941. { Built-in preprocessor }
  942. type
  943. EBuiltinPreprocessScriptError = class(Exception);
  944. function BuiltinPreprocessScript(var Params: TPreprocessScriptParams): Integer; stdcall;
  945. var
  946. IncludeStack: TStringList;
  947. procedure RaiseError(const LineFilename: String; const LineNumber: Integer;
  948. const Msg: String);
  949. begin
  950. Params.ErrorProc(Params.CompilerData, PChar(Msg), PChar(LineFilename),
  951. LineNumber, 0);
  952. { Note: This exception is caught and translated into ispePreprocessError }
  953. raise EBuiltinPreprocessScriptError.Create('BuiltinPreprocessScript error');
  954. end;
  955. procedure ProcessLines(const Filename: String; const FileHandle: TPreprocFileHandle);
  956. forward;
  957. procedure ProcessLinesFromFile(const LineFilename: String;
  958. const LineNumber: Integer; const IncludeFilename: String);
  959. var
  960. I: Integer;
  961. FileHandle: TPreprocFileHandle;
  962. begin
  963. { Check if it's a recursive include }
  964. for I := 0 to IncludeStack.Count-1 do
  965. if PathCompare(IncludeStack[I], IncludeFilename) = 0 then
  966. RaiseError(LineFilename, LineNumber, Format(SCompilerRecursiveInclude,
  967. [IncludeFilename]));
  968. FileHandle := Params.LoadFileProc(Params.CompilerData,
  969. PChar(IncludeFilename), PChar(LineFilename), LineNumber, 0);
  970. if FileHandle < 0 then begin
  971. { Note: The message here shouldn't be seen as LoadFileProc should have
  972. already called ErrorProc itself }
  973. RaiseError(LineFilename, LineNumber, 'LoadFileProc failed');
  974. end;
  975. ProcessLines(IncludeFilename, FileHandle);
  976. end;
  977. procedure ProcessDirective(const LineFilename: String; const LineNumber: Integer;
  978. D: String);
  979. var
  980. Dir, IncludeFilename: String;
  981. begin
  982. if Copy(D, 1, Length('include')) = 'include' then begin
  983. Delete(D, 1, Length('include'));
  984. if (D = '') or (D[1] > ' ') then
  985. RaiseError(LineFilename, LineNumber, SCompilerInvalidDirective);
  986. D := TrimLeft(D);
  987. if (Length(D) < 3) or (D[1] <> '"') or (PathLastChar(D)^ <> '"') then
  988. RaiseError(LineFilename, LineNumber, SCompilerInvalidDirective);
  989. if LineFilename = '' then
  990. Dir := Params.SourcePath
  991. else
  992. Dir := PathExtractPath(LineFilename);
  993. IncludeFilename := Params.PrependDirNameProc(Params.CompilerData,
  994. PChar(RemoveQuotes(D)), PChar(Dir), PChar(LineFilename), LineNumber, 0);
  995. if IncludeFilename = '' then begin
  996. { Note: The message here shouldn't be seen as PrependDirNameProc
  997. should have already called ErrorProc itself }
  998. RaiseError(LineFilename, LineNumber, 'PrependDirNameProc failed');
  999. end;
  1000. Params.StatusProc(Params.CompilerData,
  1001. PChar(Format(SBuiltinPreprocessStatusIncludingFile, [IncludeFilename])), False);
  1002. ProcessLinesFromFile(LineFilename, LineNumber, PathExpand(IncludeFilename));
  1003. end
  1004. else
  1005. RaiseError(LineFilename, LineNumber, SCompilerInvalidDirective);
  1006. end;
  1007. procedure ProcessLines(const Filename: String; const FileHandle: TPreprocFileHandle);
  1008. var
  1009. I: Integer;
  1010. LineText, L: PChar;
  1011. begin
  1012. IncludeStack.Add(Filename);
  1013. I := 0;
  1014. while True do begin
  1015. LineText := Params.LineInProc(Params.CompilerData, FileHandle, I);
  1016. if LineText = nil then
  1017. Break;
  1018. L := LineText;
  1019. SkipWhitespace(L);
  1020. if L^ = '#' then
  1021. ProcessDirective(Filename, I + 1, L + 1)
  1022. else
  1023. Params.LineOutProc(Params.CompilerData, PChar(Filename), I + 1,
  1024. LineText);
  1025. Inc(I);
  1026. end;
  1027. IncludeStack.Delete(IncludeStack.Count-1);
  1028. end;
  1029. begin
  1030. if (Params.Size <> SizeOf(Params)) or
  1031. (Params.InterfaceVersion <> 2) then begin
  1032. Result := ispeInvalidParam;
  1033. Exit;
  1034. end;
  1035. try
  1036. IncludeStack := TStringList.Create;
  1037. try
  1038. ProcessLines(Params.Filename, 0);
  1039. finally
  1040. IncludeStack.Free;
  1041. end;
  1042. Result := ispeSuccess;
  1043. except
  1044. Result := ispePreprocessError;
  1045. if not(ExceptObject is EBuiltinPreprocessScriptError) then
  1046. raise;
  1047. end;
  1048. end;
  1049. { TCompressionHandler }
  1050. type
  1051. TCompressionHandler = class
  1052. private
  1053. FCachedCompressors: TLowFragList;
  1054. FCompiler: TSetupCompiler;
  1055. FCompressor: TCustomCompressor;
  1056. FChunkBytesRead: Integer64;
  1057. FChunkBytesWritten: Integer64;
  1058. FChunkEncrypted: Boolean;
  1059. FChunkFirstSlice: Integer;
  1060. FChunkStarted: Boolean;
  1061. FChunkStartOffset: Longint;
  1062. FCryptContext: TArcFourContext;
  1063. FCurSlice: Integer;
  1064. FDestFile: TFile;
  1065. FDestFileIsDiskSlice: Boolean;
  1066. FInitialBytesCompressedSoFar: Integer64;
  1067. FSliceBaseOffset: Cardinal;
  1068. FSliceBytesLeft: Cardinal;
  1069. procedure EndSlice;
  1070. procedure NewSlice(const Filename: String);
  1071. public
  1072. constructor Create(ACompiler: TSetupCompiler; const InitialSliceFilename: String);
  1073. destructor Destroy; override;
  1074. procedure CompressFile(const SourceFile: TFile; Bytes: Integer64;
  1075. const CallOptimize: Boolean; var SHA1Sum: TSHA1Digest);
  1076. procedure EndChunk;
  1077. procedure Finish;
  1078. procedure NewChunk(const ACompressorClass: TCustomCompressorClass;
  1079. const ACompressLevel: Integer; const ACompressorProps: TCompressorProps;
  1080. const AUseEncryption: Boolean; const ACryptKey: String);
  1081. procedure ProgressProc(BytesProcessed: Cardinal);
  1082. function ReserveBytesOnSlice(const Bytes: Cardinal): Boolean;
  1083. procedure WriteProc(const Buf; BufSize: Longint);
  1084. property ChunkBytesRead: Integer64 read FChunkBytesRead;
  1085. property ChunkBytesWritten: Integer64 read FChunkBytesWritten;
  1086. property ChunkEncrypted: Boolean read FChunkEncrypted;
  1087. property ChunkFirstSlice: Integer read FChunkFirstSlice;
  1088. property ChunkStartOffset: Longint read FChunkStartOffset;
  1089. property ChunkStarted: Boolean read FChunkStarted;
  1090. property CurSlice: Integer read FCurSlice;
  1091. end;
  1092. constructor TCompressionHandler.Create(ACompiler: TSetupCompiler;
  1093. const InitialSliceFilename: String);
  1094. begin
  1095. inherited Create;
  1096. FCompiler := ACompiler;
  1097. FCurSlice := -1;
  1098. FCachedCompressors := TLowFragList.Create;
  1099. NewSlice(InitialSliceFilename);
  1100. end;
  1101. destructor TCompressionHandler.Destroy;
  1102. var
  1103. I: Integer;
  1104. begin
  1105. if Assigned(FCachedCompressors) then begin
  1106. for I := FCachedCompressors.Count-1 downto 0 do
  1107. TCustomCompressor(FCachedCompressors[I]).Free;
  1108. FreeAndNil(FCachedCompressors);
  1109. end;
  1110. FreeAndNil(FDestFile);
  1111. inherited;
  1112. end;
  1113. procedure TCompressionHandler.Finish;
  1114. begin
  1115. EndChunk;
  1116. EndSlice;
  1117. end;
  1118. procedure TCompressionHandler.EndSlice;
  1119. var
  1120. DiskSliceHeader: TDiskSliceHeader;
  1121. begin
  1122. if Assigned(FDestFile) then begin
  1123. if FDestFileIsDiskSlice then begin
  1124. DiskSliceHeader.TotalSize := FDestFile.Size.Lo;
  1125. FDestFile.Seek(SizeOf(DiskSliceID));
  1126. FDestFile.WriteBuffer(DiskSliceHeader, SizeOf(DiskSliceHeader));
  1127. end;
  1128. FreeAndNil(FDestFile);
  1129. end;
  1130. end;
  1131. procedure TCompressionHandler.NewSlice(const Filename: String);
  1132. function GenerateSliceFilename(const Compiler: TSetupCompiler;
  1133. const ASlice: Integer): String;
  1134. var
  1135. Major, Minor: Integer;
  1136. begin
  1137. Major := ASlice div Compiler.SlicesPerDisk + 1;
  1138. Minor := ASlice mod Compiler.SlicesPerDisk;
  1139. if Compiler.SlicesPerDisk = 1 then
  1140. Result := Format('%s-%d.bin', [Compiler.OutputBaseFilename, Major])
  1141. else
  1142. Result := Format('%s-%d%s.bin', [Compiler.OutputBaseFilename, Major,
  1143. Chr(Ord('a') + Minor)]);
  1144. end;
  1145. var
  1146. DiskHeader: TDiskSliceHeader;
  1147. begin
  1148. EndSlice;
  1149. Inc(FCurSlice);
  1150. if (FCurSlice > 0) and not FCompiler.DiskSpanning then
  1151. FCompiler.AbortCompileFmt(SCompilerMustUseDiskSpanning,
  1152. [FCompiler.DiskSliceSize]);
  1153. if Filename = '' then begin
  1154. FDestFileIsDiskSlice := True;
  1155. FDestFile := TFile.Create(FCompiler.OutputDir +
  1156. GenerateSliceFilename(FCompiler, FCurSlice), fdCreateAlways, faReadWrite, fsNone);
  1157. FDestFile.WriteBuffer(DiskSliceID, SizeOf(DiskSliceID));
  1158. DiskHeader.TotalSize := 0;
  1159. FDestFile.WriteBuffer(DiskHeader, SizeOf(DiskHeader));
  1160. FSliceBaseOffset := 0;
  1161. FSliceBytesLeft := FCompiler.DiskSliceSize - (SizeOf(DiskSliceID) + SizeOf(DiskHeader));
  1162. end
  1163. else begin
  1164. FDestFileIsDiskSlice := False;
  1165. FDestFile := TFile.Create(Filename, fdOpenExisting, faReadWrite, fsNone);
  1166. FDestFile.SeekToEnd;
  1167. FSliceBaseOffset := FDestFile.Position.Lo;
  1168. FSliceBytesLeft := Cardinal(FCompiler.DiskSliceSize) - FSliceBaseOffset;
  1169. end;
  1170. end;
  1171. function TCompressionHandler.ReserveBytesOnSlice(const Bytes: Cardinal): Boolean;
  1172. begin
  1173. if FSliceBytesLeft >= Bytes then begin
  1174. Dec(FSliceBytesLeft, Bytes);
  1175. Result := True;
  1176. end
  1177. else
  1178. Result := False;
  1179. end;
  1180. procedure TCompressionHandler.NewChunk(const ACompressorClass: TCustomCompressorClass;
  1181. const ACompressLevel: Integer; const ACompressorProps: TCompressorProps;
  1182. const AUseEncryption: Boolean; const ACryptKey: String);
  1183. procedure SelectCompressor;
  1184. var
  1185. I: Integer;
  1186. C: TCustomCompressor;
  1187. begin
  1188. { No current compressor, or changing compressor classes? }
  1189. if (FCompressor = nil) or (FCompressor.ClassType <> ACompressorClass) then begin
  1190. FCompressor := nil;
  1191. { Search cache for requested class }
  1192. for I := FCachedCompressors.Count-1 downto 0 do begin
  1193. C := FCachedCompressors[I];
  1194. if C.ClassType = ACompressorClass then begin
  1195. FCompressor := C;
  1196. Break;
  1197. end;
  1198. end;
  1199. end;
  1200. if FCompressor = nil then begin
  1201. FCachedCompressors.Expand;
  1202. FCompressor := ACompressorClass.Create(WriteProc, ProgressProc,
  1203. ACompressLevel, ACompressorProps);
  1204. FCachedCompressors.Add(FCompressor);
  1205. end;
  1206. end;
  1207. procedure InitEncryption;
  1208. var
  1209. Salt: TSetupSalt;
  1210. Context: TSHA1Context;
  1211. Hash: TSHA1Digest;
  1212. begin
  1213. { Generate and write a random salt. This salt is hashed into the key to
  1214. prevent the same key from ever being used twice (theoretically). }
  1215. GenerateRandomBytes(Salt, SizeOf(Salt));
  1216. FDestFile.WriteBuffer(Salt, SizeOf(Salt));
  1217. { Create an SHA-1 hash of the salt plus ACryptKey, and use that as the key }
  1218. SHA1Init(Context);
  1219. SHA1Update(Context, Salt, SizeOf(Salt));
  1220. SHA1Update(Context, Pointer(ACryptKey)^, Length(ACryptKey)*SizeOf(ACryptKey[1]));
  1221. Hash := SHA1Final(Context);
  1222. ArcFourInit(FCryptContext, Hash, SizeOf(Hash));
  1223. { Discard first 1000 bytes of the output keystream, since according to
  1224. <http://en.wikipedia.org/wiki/RC4_(cipher)>, "the first few bytes of
  1225. output keystream are strongly non-random." }
  1226. ArcFourDiscard(FCryptContext, 1000);
  1227. end;
  1228. var
  1229. MinBytesLeft: Cardinal;
  1230. begin
  1231. EndChunk;
  1232. { If there isn't enough room left to start a new chunk on the current slice,
  1233. start a new slice }
  1234. MinBytesLeft := SizeOf(ZLIBID);
  1235. if AUseEncryption then
  1236. Inc(MinBytesLeft, SizeOf(TSetupSalt));
  1237. Inc(MinBytesLeft); { for at least one byte of data }
  1238. if FSliceBytesLeft < MinBytesLeft then
  1239. NewSlice('');
  1240. FChunkFirstSlice := FCurSlice;
  1241. FChunkStartOffset := FDestFile.Position.Lo - FSliceBaseOffset;
  1242. FDestFile.WriteBuffer(ZLIBID, SizeOf(ZLIBID));
  1243. Dec(FSliceBytesLeft, SizeOf(ZLIBID));
  1244. FChunkBytesRead.Hi := 0;
  1245. FChunkBytesRead.Lo := 0;
  1246. FChunkBytesWritten.Hi := 0;
  1247. FChunkBytesWritten.Lo := 0;
  1248. FInitialBytesCompressedSoFar := FCompiler.BytesCompressedSoFar;
  1249. SelectCompressor;
  1250. FChunkEncrypted := AUseEncryption;
  1251. if AUseEncryption then
  1252. InitEncryption;
  1253. FChunkStarted := True;
  1254. end;
  1255. procedure TCompressionHandler.EndChunk;
  1256. begin
  1257. if Assigned(FCompressor) then begin
  1258. FCompressor.Finish;
  1259. { In case we didn't get a ProgressProc call after the final block: }
  1260. FCompiler.BytesCompressedSoFar := FInitialBytesCompressedSoFar;
  1261. Inc6464(FCompiler.BytesCompressedSoFar, FChunkBytesRead);
  1262. FCompiler.CallIdleProc;
  1263. end;
  1264. FChunkStarted := False;
  1265. end;
  1266. procedure TCompressionHandler.CompressFile(const SourceFile: TFile;
  1267. Bytes: Integer64; const CallOptimize: Boolean; var SHA1Sum: TSHA1Digest);
  1268. var
  1269. Context: TSHA1Context;
  1270. AddrOffset: LongWord;
  1271. BufSize: Cardinal;
  1272. Buf: array[0..65535] of Byte;
  1273. { ^ *must* be the same buffer size used in Setup (TFileExtractor), otherwise
  1274. the TransformCallInstructions call will break }
  1275. begin
  1276. SHA1Init(Context);
  1277. AddrOffset := 0;
  1278. while True do begin
  1279. BufSize := SizeOf(Buf);
  1280. if (Bytes.Hi = 0) and (Bytes.Lo < BufSize) then
  1281. BufSize := Bytes.Lo;
  1282. if BufSize = 0 then
  1283. Break;
  1284. SourceFile.ReadBuffer(Buf, BufSize);
  1285. Inc64(FChunkBytesRead, BufSize);
  1286. Dec64(Bytes, BufSize);
  1287. SHA1Update(Context, Buf, BufSize);
  1288. if CallOptimize then begin
  1289. TransformCallInstructions(Buf, BufSize, True, AddrOffset);
  1290. Inc(AddrOffset, BufSize); { may wrap, but OK }
  1291. end;
  1292. FCompressor.Compress(Buf, BufSize);
  1293. end;
  1294. SHA1Sum := SHA1Final(Context);
  1295. end;
  1296. procedure TCompressionHandler.WriteProc(const Buf; BufSize: Longint);
  1297. var
  1298. P, P2: Pointer;
  1299. S: Cardinal;
  1300. begin
  1301. FCompiler.CallIdleProc;
  1302. P := @Buf;
  1303. while BufSize > 0 do begin
  1304. S := BufSize;
  1305. if FSliceBytesLeft = 0 then
  1306. NewSlice('');
  1307. if S > Cardinal(FSliceBytesLeft) then
  1308. S := FSliceBytesLeft;
  1309. if not FChunkEncrypted then
  1310. FDestFile.WriteBuffer(P^, S)
  1311. else begin
  1312. { Using encryption. Can't modify Buf in place so allocate a new,
  1313. temporary buffer. }
  1314. GetMem(P2, S);
  1315. try
  1316. ArcFourCrypt(FCryptContext, P^, P2^, S);
  1317. FDestFile.WriteBuffer(P2^, S)
  1318. finally
  1319. FreeMem(P2);
  1320. end;
  1321. end;
  1322. Inc64(FChunkBytesWritten, S);
  1323. Inc(Cardinal(P), S);
  1324. Dec(BufSize, S);
  1325. Dec(FSliceBytesLeft, S);
  1326. end;
  1327. end;
  1328. procedure TCompressionHandler.ProgressProc(BytesProcessed: Cardinal);
  1329. begin
  1330. Inc64(FCompiler.BytesCompressedSoFar, BytesProcessed);
  1331. FCompiler.CallIdleProc;
  1332. end;
  1333. { TSetupCompiler }
  1334. constructor TSetupCompiler.Create(AOwner: TComponent);
  1335. begin
  1336. inherited Create;
  1337. ScriptFiles := TStringList.Create;
  1338. LanguageEntries := TLowFragList.Create;
  1339. CustomMessageEntries := TLowFragList.Create;
  1340. PermissionEntries := TLowFragList.Create;
  1341. TypeEntries := TLowFragList.Create;
  1342. ComponentEntries := TLowFragList.Create;
  1343. TaskEntries := TLowFragList.Create;
  1344. DirEntries := TLowFragList.Create;
  1345. FileEntries := TLowFragList.Create;
  1346. FileLocationEntries := TLowFragList.Create;
  1347. IconEntries := TLowFragList.Create;
  1348. IniEntries := TLowFragList.Create;
  1349. RegistryEntries := TLowFragList.Create;
  1350. InstallDeleteEntries := TLowFragList.Create;
  1351. UninstallDeleteEntries := TLowFragList.Create;
  1352. RunEntries := TLowFragList.Create;
  1353. UninstallRunEntries := TLowFragList.Create;
  1354. FileLocationEntryFilenames := THashStringList.Create;
  1355. WarningsList := THashStringList.Create;
  1356. WarningsList.IgnoreDuplicates := True;
  1357. ExpectedCustomMessageNames := TStringList.Create;
  1358. UsedUserAreas := TStringList.Create;
  1359. UsedUserAreas.Sorted := True;
  1360. UsedUserAreas.Duplicates := dupIgnore;
  1361. PreprocIncludedFilenames := TStringList.Create;
  1362. DefaultLangData := TLangData.Create;
  1363. PreLangDataList := TLowFragList.Create;
  1364. LangDataList := TLowFragList.Create;
  1365. SignToolList := TLowFragList.Create;
  1366. SignTools := TStringList.Create;
  1367. SignToolsParams := TStringList.Create;
  1368. DebugInfo := TMemoryStream.Create;
  1369. CodeDebugInfo := TMemoryStream.Create;
  1370. CodeText := TStringList.Create;
  1371. CodeCompiler := TScriptCompiler.Create;
  1372. CodeCompiler.NamingAttribute := 'Event';
  1373. CodeCompiler.OnLineToLineInfo := CodeCompilerOnLineToLineInfo;
  1374. CodeCompiler.OnUsedLine := CodeCompilerOnUsedLine;
  1375. CodeCompiler.OnUsedVariable := CodeCompilerOnUsedVariable;
  1376. CodeCompiler.OnError := CodeCompilerOnError;
  1377. CodeCompiler.OnWarning := CodeCompilerOnWarning;
  1378. end;
  1379. destructor TSetupCompiler.Destroy;
  1380. var
  1381. I: Integer;
  1382. begin
  1383. CodeCompiler.Free;
  1384. CodeText.Free;
  1385. CodeDebugInfo.Free;
  1386. DebugInfo.Free;
  1387. SignToolsParams.Free;
  1388. SignTools.Free;
  1389. if Assigned(SignToolList) then begin
  1390. for I := 0 to SignToolList.Count-1 do
  1391. TSignTool(SignToolList[I]).Free;
  1392. SignToolList.Free;
  1393. end;
  1394. LangDataList.Free;
  1395. PreLangDataList.Free;
  1396. DefaultLangData.Free;
  1397. PreprocIncludedFilenames.Free;
  1398. UsedUserAreas.Free;
  1399. ExpectedCustomMessageNames.Free;
  1400. WarningsList.Free;
  1401. FileLocationEntryFilenames.Free;
  1402. UninstallRunEntries.Free;
  1403. RunEntries.Free;
  1404. UninstallDeleteEntries.Free;
  1405. InstallDeleteEntries.Free;
  1406. RegistryEntries.Free;
  1407. IniEntries.Free;
  1408. IconEntries.Free;
  1409. FileLocationEntries.Free;
  1410. FileEntries.Free;
  1411. DirEntries.Free;
  1412. TaskEntries.Free;
  1413. ComponentEntries.Free;
  1414. TypeEntries.Free;
  1415. PermissionEntries.Free;
  1416. CustomMessageEntries.Free;
  1417. LanguageEntries.Free;
  1418. ScriptFiles.Free;
  1419. inherited Destroy;
  1420. end;
  1421. procedure TSetupCompiler.InitPreprocessor;
  1422. {$IFNDEF STATICPREPROC}
  1423. var
  1424. Filename: String;
  1425. Attr: DWORD;
  1426. M: HMODULE;
  1427. {$ENDIF}
  1428. begin
  1429. if PreprocessorInitialized then
  1430. Exit;
  1431. {$IFNDEF STATICPREPROC}
  1432. Filename := CompilerDir + 'ISPP.dll';
  1433. Attr := GetFileAttributes(PChar(Filename));
  1434. if (Attr = $FFFFFFFF) and (GetLastError = ERROR_FILE_NOT_FOUND) then begin
  1435. { ISPP unavailable; fall back to built-in preprocessor }
  1436. end
  1437. else begin
  1438. M := SafeLoadLibrary(Filename, SEM_NOOPENFILEERRORBOX);
  1439. if M = 0 then
  1440. AbortCompileFmt('Failed to load preprocessor DLL "%s" (%d)',
  1441. [Filename, GetLastError]);
  1442. PreprocessScriptProc := GetProcAddress(M, 'ISPreprocessScriptW');
  1443. if not Assigned(PreprocessScriptProc) then
  1444. AbortCompileFmt('Failed to get address of functions in "%s"', [Filename]);
  1445. end;
  1446. {$ELSE}
  1447. PreprocessScriptProc := ISPreprocessScript;
  1448. {$ENDIF}
  1449. PreprocessorInitialized := True;
  1450. end;
  1451. procedure TSetupCompiler.InitZipDLL;
  1452. var
  1453. M: HMODULE;
  1454. begin
  1455. if ZipInitialized then
  1456. Exit;
  1457. M := SafeLoadLibrary(CompilerDir + 'iszlib.dll', SEM_NOOPENFILEERRORBOX);
  1458. if M = 0 then
  1459. AbortCompileFmt('Failed to load iszlib.dll (%d)', [GetLastError]);
  1460. if not ZlibInitCompressFunctions(M) then
  1461. AbortCompile('Failed to get address of functions in iszlib.dll');
  1462. ZipInitialized := True;
  1463. end;
  1464. procedure TSetupCompiler.InitBzipDLL;
  1465. var
  1466. M: HMODULE;
  1467. begin
  1468. if BzipInitialized then
  1469. Exit;
  1470. M := SafeLoadLibrary(CompilerDir + 'isbzip.dll', SEM_NOOPENFILEERRORBOX);
  1471. if M = 0 then
  1472. AbortCompileFmt('Failed to load isbzip.dll (%d)', [GetLastError]);
  1473. if not BZInitCompressFunctions(M) then
  1474. AbortCompile('Failed to get address of functions in isbzip.dll');
  1475. BzipInitialized := True;
  1476. end;
  1477. procedure TSetupCompiler.InitLZMADLL;
  1478. var
  1479. M: HMODULE;
  1480. begin
  1481. if LZMAInitialized then
  1482. Exit;
  1483. M := SafeLoadLibrary(CompilerDir + 'islzma.dll', SEM_NOOPENFILEERRORBOX);
  1484. if M = 0 then
  1485. AbortCompileFmt('Failed to load islzma.dll (%d)', [GetLastError]);
  1486. if not LZMAInitCompressFunctions(M) then
  1487. AbortCompile('Failed to get address of functions in islzma.dll');
  1488. LZMAInitialized := True;
  1489. end;
  1490. function TSetupCompiler.GetLZMAExeFilename(const Allow64Bit: Boolean): String;
  1491. const
  1492. PROCESSOR_ARCHITECTURE_AMD64 = 9;
  1493. ExeFilenames: array[Boolean] of String = ('islzma32.exe', 'islzma64.exe');
  1494. var
  1495. UseX64Exe: Boolean;
  1496. GetNativeSystemInfoFunc: procedure(var lpSystemInfo: TSystemInfo); stdcall;
  1497. SysInfo: TSystemInfo;
  1498. begin
  1499. UseX64Exe := False;
  1500. if Allow64Bit then begin
  1501. GetNativeSystemInfoFunc := GetProcAddress(GetModuleHandle(kernel32),
  1502. 'GetNativeSystemInfo');
  1503. if Assigned(GetNativeSystemInfoFunc) then begin
  1504. GetNativeSystemInfoFunc(SysInfo);
  1505. if SysInfo.wProcessorArchitecture = PROCESSOR_ARCHITECTURE_AMD64 then
  1506. UseX64Exe := True;
  1507. end;
  1508. end;
  1509. Result := CompilerDir + ExeFilenames[UseX64Exe];
  1510. end;
  1511. procedure TSetupCompiler.InitCryptDLL;
  1512. var
  1513. M: HMODULE;
  1514. begin
  1515. if CryptInitialized then
  1516. Exit;
  1517. M := SafeLoadLibrary(CompilerDir + 'iscrypt.dll', SEM_NOOPENFILEERRORBOX);
  1518. if M = 0 then
  1519. AbortCompileFmt('Failed to load iscrypt.dll (%d)', [GetLastError]);
  1520. if not ArcFourInitFunctions(M) then
  1521. AbortCompile('Failed to get address of functions in iscrypt.dll');
  1522. CryptInitialized := True;
  1523. end;
  1524. function TSetupCompiler.FilenameToFileIndex(const AFilename: String): Integer;
  1525. begin
  1526. if not GotPrevFilename or (PathCompare(AFilename, PrevFilename) <> 0) then begin
  1527. { AFilename is non-empty when an include file is being read or when the compiler is reading
  1528. CustomMessages/LangOptions/Messages sections from a messages file. Since these sections don't
  1529. generate debug entries we can treat an empty AFileName as the main script and a non-empty
  1530. AFilename as an include file. This works even when command-line compilation is used. }
  1531. if AFilename = '' then
  1532. PrevFileIndex := -1
  1533. else begin
  1534. PrevFileIndex := PreprocIncludedFilenames.IndexOf(AFilename);
  1535. if PrevFileIndex = -1 then
  1536. AbortCompileFmt('Failed to find index of file (%s)', [AFilename]);
  1537. end;
  1538. PrevFilename := AFilename;
  1539. GotPrevFilename := True;
  1540. end;
  1541. Result := PrevFileIndex;
  1542. end;
  1543. procedure TSetupCompiler.WriteDebugEntry(Kind: TDebugEntryKind; Index: Integer; StepOutMarker: Boolean = False);
  1544. var
  1545. Rec: TDebugEntry;
  1546. begin
  1547. Rec.FileIndex := FilenameToFileIndex(LineFilename);
  1548. Rec.LineNumber := LineNumber;
  1549. Rec.Kind := Ord(Kind);
  1550. Rec.Index := Index;
  1551. Rec.StepOutMarker := StepOutMarker;
  1552. DebugInfo.WriteBuffer(Rec, SizeOf(Rec));
  1553. Inc(DebugEntryCount);
  1554. end;
  1555. procedure TSetupCompiler.WriteCompiledCodeText(const CompiledCodeText: AnsiString);
  1556. begin
  1557. CompiledCodeTextLength := Length(CompiledCodeText);
  1558. CodeDebugInfo.WriteBuffer(CompiledCodeText[1], CompiledCodeTextLength);
  1559. end;
  1560. procedure TSetupCompiler.WriteCompiledCodeDebugInfo(const CompiledCodeDebugInfo: AnsiString);
  1561. begin
  1562. CompiledCodeDebugInfoLength := Length(CompiledCodeDebugInfo);
  1563. CodeDebugInfo.WriteBuffer(CompiledCodeDebugInfo[1], CompiledCodeDebugInfoLength);
  1564. end;
  1565. procedure TSetupCompiler.ShiftDebugEntryIndexes(AKind: TDebugEntryKind);
  1566. { Increments the Index field of each debug entry of the specified kind by 1.
  1567. This has to be called when a new entry is inserted at the *front* of an
  1568. *Entries array, since doing that causes the indexes of existing entries to
  1569. shift. }
  1570. var
  1571. Rec: PDebugEntry;
  1572. I: Integer;
  1573. begin
  1574. Cardinal(Rec) := Cardinal(DebugInfo.Memory) + SizeOf(TDebugInfoHeader);
  1575. for I := 0 to DebugEntryCount-1 do begin
  1576. if Rec.Kind = Ord(AKind) then
  1577. Inc(Rec.Index);
  1578. Inc(Rec);
  1579. end;
  1580. end;
  1581. procedure TSetupCompiler.DoCallback(const Code: Integer;
  1582. var Data: TCompilerCallbackData);
  1583. begin
  1584. case CallbackProc(Code, Data, AppData) of
  1585. iscrSuccess: ;
  1586. iscrRequestAbort: Abort;
  1587. else
  1588. AbortCompile('CallbackProc return code invalid');
  1589. end;
  1590. end;
  1591. procedure TSetupCompiler.CallIdleProc;
  1592. const
  1593. ProgressMax = 1024;
  1594. var
  1595. Data: TCompilerCallbackData;
  1596. MillisecondsElapsed: Cardinal;
  1597. X: Integer64;
  1598. begin
  1599. Data.SecondsRemaining := -1;
  1600. Data.BytesCompressedPerSecond := 0;
  1601. if ((BytesCompressedSoFar.Lo = 0) and (BytesCompressedSoFar.Hi = 0)) or
  1602. ((TotalBytesToCompress.Lo = 0) and (TotalBytesToCompress.Hi = 0)) then begin
  1603. { Optimization(?) and avoid division by zero when TotalBytesToCompress=0 }
  1604. Data.CompressProgress := 0;
  1605. end
  1606. else begin
  1607. Data.CompressProgress := Trunc((Comp(BytesCompressedSoFar) * ProgressMax) /
  1608. Comp(TotalBytesToCompress));
  1609. { In case one of the files got bigger since we checked the sizes... }
  1610. if Data.CompressProgress > ProgressMax then
  1611. Data.CompressProgress := ProgressMax;
  1612. if CompressionInProgress then begin
  1613. MillisecondsElapsed := GetTickCount - CompressionStartTick;
  1614. if MillisecondsElapsed >= Cardinal(1000) then begin
  1615. X := BytesCompressedSoFar;
  1616. Mul64(X, 1000);
  1617. Div64(X, MillisecondsElapsed);
  1618. if (X.Hi = 0) and (Longint(X.Lo) >= 0) then
  1619. Data.BytesCompressedPerSecond := X.Lo
  1620. else
  1621. Data.BytesCompressedPerSecond := Maxint;
  1622. if Compare64(BytesCompressedSoFar, TotalBytesToCompress) < 0 then begin
  1623. { Protect against division by zero }
  1624. if Data.BytesCompressedPerSecond <> 0 then begin
  1625. X := TotalBytesToCompress;
  1626. Dec6464(X, BytesCompressedSoFar);
  1627. Inc64(X, Data.BytesCompressedPerSecond-1); { round up }
  1628. Div64(X, Data.BytesCompressedPerSecond);
  1629. if (X.Hi = 0) and (Longint(X.Lo) >= 0) then
  1630. Data.SecondsRemaining := X.Lo
  1631. else
  1632. Data.SecondsRemaining := Maxint;
  1633. end;
  1634. end
  1635. else begin
  1636. { In case one of the files got bigger since we checked the sizes... }
  1637. Data.SecondsRemaining := 0;
  1638. end;
  1639. end;
  1640. end;
  1641. end;
  1642. Data.CompressProgressMax := ProgressMax;
  1643. DoCallback(iscbNotifyIdle, Data);
  1644. end;
  1645. type
  1646. PPreCompilerData = ^TPreCompilerData;
  1647. TPreCompilerData = record
  1648. Compiler: TSetupCompiler;
  1649. MainScript: Boolean;
  1650. InFiles: TStringList;
  1651. OutLines: TScriptFileLines;
  1652. AnsiConvertCodePage: Cardinal;
  1653. CurInLine: String;
  1654. ErrorSet: Boolean;
  1655. ErrorMsg, ErrorFilename: String;
  1656. ErrorLine, ErrorColumn: Integer;
  1657. LastPrependDirNameResult: String;
  1658. end;
  1659. procedure PreErrorProc(CompilerData: TPreprocCompilerData; ErrorMsg: PChar;
  1660. ErrorFilename: PChar; ErrorLine: Integer; ErrorColumn: Integer); stdcall; forward;
  1661. function LoadFile(CompilerData: TPreprocCompilerData; AFilename: PChar;
  1662. ErrorFilename: PChar; ErrorLine: Integer; ErrorColumn: Integer; FromPreProcessor: Boolean): TPreprocFileHandle;
  1663. var
  1664. Data: PPreCompilerData;
  1665. Filename: String;
  1666. I: Integer;
  1667. Lines: TLowFragStringList;
  1668. F: TTextFileReader;
  1669. L: String;
  1670. begin
  1671. Data := CompilerData;
  1672. Filename := AFilename;
  1673. if Filename = '' then begin
  1674. { Reject any attempt by the preprocessor to load the main script }
  1675. PreErrorProc(CompilerData, 'Invalid parameter passed to PreLoadFileProc',
  1676. ErrorFilename, ErrorLine, ErrorColumn);
  1677. Result := -1;
  1678. Exit;
  1679. end;
  1680. Filename := PathExpand(Filename);
  1681. for I := 0 to Data.InFiles.Count-1 do
  1682. if PathCompare(Data.InFiles[I], Filename) = 0 then begin
  1683. Result := I;
  1684. Exit;
  1685. end;
  1686. Lines := TLowFragStringList.Create;
  1687. try
  1688. if FromPreProcessor then begin
  1689. Data.Compiler.AddStatus(Format(SCompilerStatusReadingInFile, [Filename]));
  1690. if Data.MainScript then
  1691. Data.Compiler.PreprocIncludedFilenames.Add(Filename);
  1692. end;
  1693. F := TTextFileReader.Create(Filename, fdOpenExisting, faRead, fsRead);
  1694. try
  1695. F.CodePage := Data.AnsiConvertCodePage;
  1696. while not F.Eof do begin
  1697. L := F.ReadLine;
  1698. for I := 1 to Length(L) do
  1699. if L[I] = #0 then
  1700. raise Exception.CreateFmt(SCompilerIllegalNullChar, [Lines.Count + 1]);
  1701. Lines.Add(L);
  1702. end;
  1703. finally
  1704. F.Free;
  1705. end;
  1706. except
  1707. Lines.Free;
  1708. PreErrorProc(CompilerData, PChar(Format(SCompilerErrorOpeningIncludeFile,
  1709. [Filename, GetExceptMessage])), ErrorFilename, ErrorLine, ErrorColumn);
  1710. Result := -1;
  1711. Exit;
  1712. end;
  1713. Result := Data.InFiles.AddObject(Filename, Lines);
  1714. end;
  1715. function PreLoadFileProc(CompilerData: TPreprocCompilerData; AFilename: PChar;
  1716. ErrorFilename: PChar; ErrorLine: Integer; ErrorColumn: Integer): TPreprocFileHandle;
  1717. stdcall;
  1718. begin
  1719. Result := LoadFile(CompilerData, AFilename, ErrorFilename, ErrorLine, ErrorColumn, True);
  1720. end;
  1721. function PreLineInProc(CompilerData: TPreprocCompilerData;
  1722. FileHandle: TPreprocFileHandle; LineIndex: Integer): PChar; stdcall;
  1723. var
  1724. Data: PPreCompilerData;
  1725. Lines: TLowFragStringList;
  1726. begin
  1727. Data := CompilerData;
  1728. if (FileHandle >= 0) and (FileHandle < Data.InFiles.Count) and
  1729. (LineIndex >= 0) then begin
  1730. Lines := TLowFragStringList(Data.InFiles.Objects[FileHandle]);
  1731. if LineIndex < Lines.Count then begin
  1732. Data.CurInLine := Lines[LineIndex];
  1733. Result := PChar(Data.CurInLine);
  1734. end
  1735. else
  1736. Result := nil;
  1737. end
  1738. else begin
  1739. PreErrorProc(CompilerData, 'Invalid parameter passed to LineInProc',
  1740. nil, 0, 0);
  1741. Result := nil;
  1742. end;
  1743. end;
  1744. procedure PreLineOutProc(CompilerData: TPreprocCompilerData;
  1745. Filename: PChar; LineNumber: Integer; Text: PChar); stdcall;
  1746. var
  1747. Data: PPreCompilerData;
  1748. begin
  1749. Data := CompilerData;
  1750. Data.OutLines.Add(Filename, LineNumber, Text);
  1751. end;
  1752. procedure PreStatusProc(CompilerData: TPreprocCompilerData;
  1753. StatusMsg: PChar; Warning: BOOL); stdcall;
  1754. var
  1755. Data: PPreCompilerData;
  1756. begin
  1757. Data := CompilerData;
  1758. Data.Compiler.AddStatus(Format(SCompilerStatusPreprocessorStatus, [StatusMsg]), Warning);
  1759. end;
  1760. procedure PreErrorProc(CompilerData: TPreprocCompilerData; ErrorMsg: PChar;
  1761. ErrorFilename: PChar; ErrorLine: Integer; ErrorColumn: Integer); stdcall;
  1762. var
  1763. Data: PPreCompilerData;
  1764. begin
  1765. Data := CompilerData;
  1766. if not Data.ErrorSet then begin
  1767. Data.ErrorMsg := ErrorMsg;
  1768. Data.ErrorFilename := ErrorFilename;
  1769. Data.ErrorLine := ErrorLine;
  1770. Data.ErrorColumn := ErrorColumn;
  1771. Data.ErrorSet := True;
  1772. end;
  1773. end;
  1774. function PrePrependDirNameProc(CompilerData: TPreprocCompilerData;
  1775. Filename: PChar; Dir: PChar; ErrorFilename: PChar; ErrorLine: Integer;
  1776. ErrorColumn: Integer): PChar; stdcall;
  1777. var
  1778. Data: PPreCompilerData;
  1779. begin
  1780. Data := CompilerData;
  1781. try
  1782. Data.LastPrependDirNameResult := Data.Compiler.PrependDirName(
  1783. PChar(Filename), PChar(Dir));
  1784. Result := PChar(Data.LastPrependDirNameResult);
  1785. except
  1786. PreErrorProc(CompilerData, PChar(GetExceptMessage), ErrorFilename,
  1787. ErrorLine, ErrorColumn);
  1788. Result := nil;
  1789. end;
  1790. end;
  1791. function TSetupCompiler.ReadScriptFile(const Filename: String;
  1792. const UseCache: Boolean; const AnsiConvertCodePage: Cardinal): TScriptFileLines;
  1793. function ReadMainScriptLines: TLowFragStringList;
  1794. var
  1795. Reset: Boolean;
  1796. Data: TCompilerCallbackData;
  1797. begin
  1798. Result := TLowFragStringList.Create;
  1799. try
  1800. Reset := True;
  1801. while True do begin
  1802. Data.Reset := Reset;
  1803. Data.LineRead := nil;
  1804. DoCallback(iscbReadScript, Data);
  1805. if Data.LineRead = nil then
  1806. Break;
  1807. Result.Add(Data.LineRead);
  1808. Reset := False;
  1809. end;
  1810. except
  1811. Result.Free;
  1812. raise;
  1813. end;
  1814. end;
  1815. function SelectPreprocessor(const Lines: TLowFragStringList): TPreprocessScriptProc;
  1816. var
  1817. S: String;
  1818. begin
  1819. { Don't allow ISPPCC to be used if ISPP.dll is missing }
  1820. if (PreprocOptionsString <> '') and not Assigned(PreprocessScriptProc) then
  1821. raise Exception.Create(SCompilerISPPMissing);
  1822. { By default, only pass the main script through ISPP }
  1823. if (Filename = '') and Assigned(PreprocessScriptProc) then
  1824. Result := PreprocessScriptProc
  1825. else
  1826. Result := BuiltinPreprocessScript;
  1827. { Check for (and remove) #preproc override directive on the first line }
  1828. if Lines.Count > 0 then begin
  1829. S := Trim(Lines[0]);
  1830. if S = '#preproc builtin' then begin
  1831. Lines[0] := '';
  1832. Result := BuiltinPreprocessScript;
  1833. end
  1834. else if S = '#preproc ispp' then begin
  1835. Lines[0] := '';
  1836. Result := PreprocessScriptProc;
  1837. if not Assigned(Result) then
  1838. raise Exception.Create(SCompilerISPPMissing);
  1839. end;
  1840. end;
  1841. end;
  1842. procedure PreprocessLines(const OutLines: TScriptFileLines);
  1843. var
  1844. LSourcePath, LCompilerPath: String;
  1845. Params: TPreprocessScriptParams;
  1846. Data: TPreCompilerData;
  1847. FileLoaded: Boolean;
  1848. ResultCode, CleanupResultCode, I: Integer;
  1849. PreProc: TPreprocessScriptProc;
  1850. begin
  1851. LSourcePath := OriginalSourceDir;
  1852. LCompilerPath := CompilerDir;
  1853. FillChar(Params, SizeOf(Params), 0);
  1854. Params.Size := SizeOf(Params);
  1855. Params.InterfaceVersion := 2;
  1856. Params.CompilerBinVersion := SetupBinVersion;
  1857. Params.Filename := PChar(Filename);
  1858. Params.SourcePath := PChar(LSourcePath);
  1859. Params.CompilerPath := PChar(LCompilerPath);
  1860. Params.Options := PChar(PreprocOptionsString);
  1861. Params.CompilerData := @Data;
  1862. Params.LoadFileProc := PreLoadFileProc;
  1863. Params.LineInProc := PreLineInProc;
  1864. Params.LineOutProc := PreLineOutProc;
  1865. Params.StatusProc := PreStatusProc;
  1866. Params.ErrorProc := PreErrorProc;
  1867. Params.PrependDirNameProc := PrePrependDirNameProc;
  1868. FillChar(Data, SizeOf(Data), 0);
  1869. Data.Compiler := Self;
  1870. Data.OutLines := OutLines;
  1871. Data.AnsiConvertCodePage := AnsiConvertCodePage;
  1872. Data.InFiles := TStringList.Create;
  1873. try
  1874. if Filename = '' then begin
  1875. Data.MainScript := True;
  1876. Data.InFiles.AddObject('', ReadMainScriptLines);
  1877. FileLoaded := True;
  1878. end
  1879. else
  1880. FileLoaded := (LoadFile(Params.CompilerData, PChar(Filename),
  1881. PChar(LineFilename), LineNumber, 0, False) = 0);
  1882. ResultCode := ispePreprocessError;
  1883. if FileLoaded then begin
  1884. PreProc := SelectPreprocessor(TLowFragStringList(Data.InFiles.Objects[0]));
  1885. if Filename = '' then
  1886. AddStatus(SCompilerStatusPreprocessing);
  1887. ResultCode := PreProc(Params);
  1888. if Filename = '' then begin
  1889. PreprocOutput := Data.Outlines.Text;
  1890. { Defer cleanup of main script until after compilation }
  1891. PreprocCleanupProcData := Params.PreprocCleanupProcData;
  1892. PreprocCleanupProc := Params.PreprocCleanupProc;
  1893. end
  1894. else if Assigned(Params.PreprocCleanupProc) then begin
  1895. CleanupResultCode := Params.PreprocCleanupProc(Params.PreprocCleanupProcData);
  1896. if CleanupResultCode <> 0 then
  1897. AbortCompileFmt('Preprocessor cleanup function for "%s" failed with code %d',
  1898. [Filename, CleanupResultCode]);
  1899. end;
  1900. end;
  1901. if Data.ErrorSet then begin
  1902. LineFilename := Data.ErrorFilename;
  1903. LineNumber := Data.ErrorLine;
  1904. if Data.ErrorColumn > 0 then { hack for now... }
  1905. Insert(Format('Column %d:' + SNewLine, [Data.ErrorColumn]),
  1906. Data.ErrorMsg, 1);
  1907. AbortCompile(Data.ErrorMsg);
  1908. end;
  1909. case ResultCode of
  1910. ispeSuccess: ;
  1911. ispeSilentAbort: Abort;
  1912. else
  1913. AbortCompileFmt('Preprocess function failed with code %d', [ResultCode]);
  1914. end;
  1915. finally
  1916. for I := Data.InFiles.Count-1 downto 0 do
  1917. Data.InFiles.Objects[I].Free;
  1918. Data.InFiles.Free;
  1919. end;
  1920. end;
  1921. var
  1922. I: Integer;
  1923. Lines: TScriptFileLines;
  1924. begin
  1925. if UseCache then
  1926. for I := 0 to ScriptFiles.Count-1 do
  1927. if PathCompare(ScriptFiles[I], Filename) = 0 then begin
  1928. Result := TScriptFileLines(ScriptFiles.Objects[I]);
  1929. Exit;
  1930. end;
  1931. Lines := TScriptFileLines.Create;
  1932. try
  1933. PreprocessLines(Lines);
  1934. except
  1935. Lines.Free;
  1936. raise;
  1937. end;
  1938. if UseCache then
  1939. ScriptFiles.AddObject(Filename, Lines);
  1940. Result := Lines;
  1941. end;
  1942. procedure TSetupCompiler.EnumIniSection(const EnumProc: TEnumIniSectionProc;
  1943. const SectionName: String; const Ext: Integer; const Verbose, SkipBlankLines: Boolean;
  1944. const Filename: String; const LangSection, LangSectionPre: Boolean);
  1945. var
  1946. FoundSection: Boolean;
  1947. LastSection: String;
  1948. procedure DoFile(Filename: String);
  1949. const
  1950. PreCodePage = 1252;
  1951. var
  1952. UseCache: Boolean;
  1953. AnsiConvertCodePage: Cardinal;
  1954. Lines: TScriptFileLines;
  1955. SaveLineFilename, L: String;
  1956. SaveLineNumber, LineIndex, I: Integer;
  1957. Line: PScriptFileLine;
  1958. begin
  1959. if Filename <> '' then
  1960. Filename := PathExpand(PrependSourceDirName(Filename));
  1961. UseCache := not (LangSection and LangSectionPre);
  1962. AnsiConvertCodePage := 0;
  1963. if LangSection then begin
  1964. { During a Pre pass on an .isl file, use code page 1252 for translation.
  1965. Previously, the system code page was used, but on DBCS that resulted in
  1966. "Illegal null character" errors on files containing byte sequences that
  1967. do not form valid lead/trail byte combinations (i.e. most languages). }
  1968. if LangSectionPre then begin
  1969. if not IsValidCodePage(PreCodePage) then { just in case }
  1970. AbortCompileFmt('Code page %u unsupported', [PreCodePage]);
  1971. AnsiConvertCodePage := PreCodePage;
  1972. end else if Ext >= 0 then begin
  1973. { Ext = LangIndex, except for Default.isl for which its -2 when default
  1974. messages are read but no special conversion is needed for those. }
  1975. AnsiConvertCodePage := TPreLangData(PreLangDataList[Ext]).LanguageCodePage;
  1976. end;
  1977. end;
  1978. Lines := ReadScriptFile(Filename, UseCache, AnsiConvertCodePage);
  1979. try
  1980. SaveLineFilename := LineFilename;
  1981. SaveLineNumber := LineNumber;
  1982. for LineIndex := 0 to Lines.Count-1 do begin
  1983. Line := Lines[LineIndex];
  1984. LineFilename := Line.LineFilename;
  1985. LineNumber := Line.LineNumber;
  1986. L := Trim(Line.LineText);
  1987. { Check for blank lines or comments }
  1988. if (not FoundSection or SkipBlankLines) and ((L = '') or (L[1] = ';')) then Continue;
  1989. if (L <> '') and (L[1] = '[') then begin
  1990. { Section tag }
  1991. I := Pos(']', L);
  1992. if (I < 3) or (I <> Length(L)) then
  1993. AbortCompileOnLine(SCompilerSectionTagInvalid);
  1994. L := Copy(L, 2, I-2);
  1995. if L[1] = '/' then begin
  1996. L := Copy(L, 2, Maxint);
  1997. if (LastSection = '') or (CompareText(L, LastSection) <> 0) then
  1998. AbortCompileOnLineFmt(SCompilerSectionBadEndTag, [L]);
  1999. FoundSection := False;
  2000. LastSection := '';
  2001. end
  2002. else begin
  2003. FoundSection := (CompareText(L, SectionName) = 0);
  2004. LastSection := L;
  2005. end;
  2006. end
  2007. else begin
  2008. if not FoundSection then begin
  2009. if LastSection = '' then
  2010. AbortCompileOnLine(SCompilerTextNotInSection);
  2011. Continue; { not on the right section }
  2012. end;
  2013. if Verbose then begin
  2014. if LineFilename = '' then
  2015. AddStatus(Format(SCompilerStatusParsingSectionLine,
  2016. [SectionName, LineNumber]))
  2017. else
  2018. AddStatus(Format(SCompilerStatusParsingSectionLineFile,
  2019. [SectionName, LineNumber, LineFilename]));
  2020. end;
  2021. EnumProc(PChar(Line.LineText), Ext);
  2022. end;
  2023. end;
  2024. LineFilename := SaveLineFilename;
  2025. LineNumber := SaveLineNumber;
  2026. finally
  2027. if not UseCache then
  2028. Lines.Free;
  2029. end;
  2030. end;
  2031. begin
  2032. FoundSection := False;
  2033. LastSection := '';
  2034. DoFile(Filename);
  2035. end;
  2036. procedure TSetupCompiler.ExtractParameters(S: PChar;
  2037. const ParamInfo: array of TParamInfo; var ParamValues: array of TParamValue);
  2038. function GetParamIndex(const AName: String): Integer;
  2039. var
  2040. I: Integer;
  2041. begin
  2042. for I := 0 to High(ParamInfo) do
  2043. if CompareText(ParamInfo[I].Name, AName) = 0 then begin
  2044. Result := I;
  2045. if ParamValues[I].Found then
  2046. AbortCompileParamError(SCompilerParamDuplicated, ParamInfo[I].Name);
  2047. ParamValues[I].Found := True;
  2048. Exit;
  2049. end;
  2050. { Unknown parameter }
  2051. AbortCompileOnLineFmt(SCompilerParamUnknownParam, [AName]);
  2052. Result := -1;
  2053. end;
  2054. var
  2055. I, ParamIndex: Integer;
  2056. ParamName, Data: String;
  2057. begin
  2058. for I := 0 to High(ParamValues) do begin
  2059. ParamValues[I].Found := False;
  2060. ParamValues[I].Data := '';
  2061. end;
  2062. while True do begin
  2063. { Parameter name }
  2064. SkipWhitespace(S);
  2065. if S^ = #0 then
  2066. Break;
  2067. ParamName := ExtractWords(S, ':');
  2068. ParamIndex := GetParamIndex(ParamName);
  2069. if S^ <> ':' then
  2070. AbortCompileOnLineFmt(SCompilerParamHasNoValue, [ParamName]);
  2071. Inc(S);
  2072. { Parameter value }
  2073. SkipWhitespace(S);
  2074. if S^ <> '"' then begin
  2075. Data := ExtractWords(S, ';');
  2076. if Pos('"', Data) <> 0 then
  2077. AbortCompileOnLineFmt(SCompilerParamQuoteError, [ParamName]);
  2078. if S^ = ';' then
  2079. Inc(S);
  2080. end
  2081. else begin
  2082. Inc(S);
  2083. Data := '';
  2084. while True do begin
  2085. if S^ = #0 then
  2086. AbortCompileOnLineFmt(SCompilerParamMissingClosingQuote, [ParamName]);
  2087. if S^ = '"' then begin
  2088. Inc(S);
  2089. if S^ <> '"' then
  2090. Break;
  2091. end;
  2092. Data := Data + S^;
  2093. Inc(S);
  2094. end;
  2095. SkipWhitespace(S);
  2096. case S^ of
  2097. #0 : ;
  2098. ';': Inc(S);
  2099. else
  2100. AbortCompileOnLineFmt(SCompilerParamQuoteError, [ParamName]);
  2101. end;
  2102. end;
  2103. { Assign the data }
  2104. if (piNoEmpty in ParamInfo[ParamIndex].Flags) and (Data = '') then
  2105. AbortCompileParamError(SCompilerParamEmpty2, ParamInfo[ParamIndex].Name);
  2106. if (piNoQuotes in ParamInfo[ParamIndex].Flags) and (Pos('"', Data) <> 0) then
  2107. AbortCompileParamError(SCompilerParamNoQuotes2, ParamInfo[ParamIndex].Name);
  2108. ParamValues[ParamIndex].Data := Data;
  2109. end;
  2110. { Check for missing required parameters }
  2111. for I := 0 to High(ParamInfo) do begin
  2112. if (piRequired in ParamInfo[I].Flags) and
  2113. not ParamValues[I].Found then
  2114. AbortCompileParamError(SCompilerParamNotSpecified, ParamInfo[I].Name);
  2115. end;
  2116. end;
  2117. procedure TSetupCompiler.AddStatus(const S: String; const Warning: Boolean);
  2118. var
  2119. Data: TCompilerCallbackData;
  2120. begin
  2121. Data.StatusMsg := PChar(S);
  2122. Data.Warning := Warning;
  2123. DoCallback(iscbNotifyStatus, Data);
  2124. end;
  2125. procedure TSetupCompiler.AddStatusFmt(const Msg: String; const Args: array of const;
  2126. const Warning: Boolean);
  2127. begin
  2128. AddStatus(Format(Msg, Args), Warning);
  2129. end;
  2130. procedure TSetupCompiler.AbortCompile(const Msg: String);
  2131. begin
  2132. raise EISCompileError.Create(Msg);
  2133. end;
  2134. procedure TSetupCompiler.AbortCompileFmt(const Msg: String; const Args: array of const);
  2135. begin
  2136. AbortCompile(Format(Msg, Args));
  2137. end;
  2138. procedure TSetupCompiler.AbortCompileOnLine(const Msg: String);
  2139. { AbortCompileOnLine is now equivalent to AbortCompile }
  2140. begin
  2141. AbortCompile(Msg);
  2142. end;
  2143. procedure TSetupCompiler.AbortCompileOnLineFmt(const Msg: String;
  2144. const Args: array of const);
  2145. begin
  2146. AbortCompileOnLine(Format(Msg, Args));
  2147. end;
  2148. procedure TSetupCompiler.AbortCompileParamError(const Msg, ParamName: String);
  2149. begin
  2150. AbortCompileOnLineFmt(Msg, [ParamName]);
  2151. end;
  2152. function TSetupCompiler.PrependDirName(const Filename, Dir: String): String;
  2153. function GetShellFolderPathCached(const FolderID: Integer;
  2154. var CachedDir: String): String;
  2155. var
  2156. S: String;
  2157. begin
  2158. if CachedDir = '' then begin
  2159. S := GetShellFolderPath(FolderID);
  2160. if S = '' then
  2161. AbortCompileFmt('Failed to get shell folder path (0x%.4x)', [FolderID]);
  2162. S := AddBackslash(PathExpand(S));
  2163. CachedDir := S;
  2164. end;
  2165. Result := CachedDir;
  2166. end;
  2167. const
  2168. CSIDL_PERSONAL = $0005;
  2169. var
  2170. P: Integer;
  2171. Prefix: String;
  2172. begin
  2173. P := PathPos(':', Filename);
  2174. if (P = 0) or
  2175. ((P = 2) and CharInSet(UpCase(Filename[1]), ['A'..'Z'])) then begin
  2176. if (Filename = '') or not IsRelativePath(Filename) then
  2177. Result := Filename
  2178. else
  2179. Result := Dir + Filename;
  2180. end
  2181. else begin
  2182. Prefix := Copy(Filename, 1, P-1);
  2183. if Prefix = 'compiler' then
  2184. Result := CompilerDir + Copy(Filename, P+1, Maxint)
  2185. else if Prefix = 'userdocs' then
  2186. Result := GetShellFolderPathCached(CSIDL_PERSONAL, CachedUserDocsDir) +
  2187. Copy(Filename, P+1, Maxint)
  2188. else begin
  2189. AbortCompileFmt(SCompilerUnknownFilenamePrefix, [Copy(Filename, 1, P)]);
  2190. Result := Filename; { avoid warning }
  2191. end;
  2192. end;
  2193. end;
  2194. function TSetupCompiler.PrependSourceDirName(const Filename: String): String;
  2195. begin
  2196. Result := PrependDirName(Filename, SourceDir);
  2197. end;
  2198. procedure TSetupCompiler.RenamedConstantCallback(const Cnst, CnstRenamed: String);
  2199. begin
  2200. if Pos('common', LowerCase(CnstRenamed)) <> 0 then
  2201. WarningsList.Add(Format(SCompilerCommonConstantRenamed, [Cnst, CnstRenamed]))
  2202. else
  2203. WarningsList.Add(Format(SCompilerConstantRenamed, [Cnst, CnstRenamed]));
  2204. end;
  2205. function TSetupCompiler.CheckConst(const S: String; const MinVersion: TSetupVersionData;
  2206. const AllowedConsts: TAllowedConsts): Boolean;
  2207. { Returns True if S contains constants. Aborts compile if they are invalid. }
  2208. function CheckEnvConst(C: String): Boolean;
  2209. { based on ExpandEnvConst in Main.pas }
  2210. var
  2211. I: Integer;
  2212. VarName, Default: String;
  2213. begin
  2214. Delete(C, 1, 1);
  2215. I := ConstPos('|', C); { check for 'default' value }
  2216. if I = 0 then
  2217. I := Length(C)+1;
  2218. VarName := Copy(C, 1, I-1);
  2219. Default := Copy(C, I+1, Maxint);
  2220. if ConvertConstPercentStr(VarName) and ConvertConstPercentStr(Default) then begin
  2221. CheckConst(VarName, MinVersion, AllowedConsts);
  2222. CheckConst(Default, MinVersion, AllowedConsts);
  2223. Result := True;
  2224. Exit;
  2225. end;
  2226. { it will only reach here if there was a parsing error }
  2227. Result := False;
  2228. end;
  2229. function CheckRegConst(C: String): Boolean;
  2230. { based on ExpandRegConst in Main.pas }
  2231. type
  2232. TKeyNameConst = packed record
  2233. KeyName: String;
  2234. KeyConst: HKEY;
  2235. end;
  2236. const
  2237. KeyNameConsts: array[0..5] of TKeyNameConst = (
  2238. (KeyName: 'HKA'; KeyConst: HKEY_AUTO),
  2239. (KeyName: 'HKCR'; KeyConst: HKEY_CLASSES_ROOT),
  2240. (KeyName: 'HKCU'; KeyConst: HKEY_CURRENT_USER),
  2241. (KeyName: 'HKLM'; KeyConst: HKEY_LOCAL_MACHINE),
  2242. (KeyName: 'HKU'; KeyConst: HKEY_USERS),
  2243. (KeyName: 'HKCC'; KeyConst: HKEY_CURRENT_CONFIG));
  2244. var
  2245. Z, Subkey, Value, Default: String;
  2246. I, J, L: Integer;
  2247. RootKey: HKEY;
  2248. begin
  2249. Delete(C, 1, 4); { skip past 'reg:' }
  2250. I := ConstPos('\', C);
  2251. if I <> 0 then begin
  2252. Z := Copy(C, 1, I-1);
  2253. if Z <> '' then begin
  2254. L := Length(Z);
  2255. if L >= 2 then begin
  2256. { Check for '32' or '64' suffix }
  2257. if ((Z[L-1] = '3') and (Z[L] = '2')) or
  2258. ((Z[L-1] = '6') and (Z[L] = '4')) then
  2259. SetLength(Z, L-2);
  2260. end;
  2261. RootKey := 0;
  2262. for J := Low(KeyNameConsts) to High(KeyNameConsts) do
  2263. if CompareText(KeyNameConsts[J].KeyName, Z) = 0 then begin
  2264. RootKey := KeyNameConsts[J].KeyConst;
  2265. Break;
  2266. end;
  2267. if RootKey <> 0 then begin
  2268. Z := Copy(C, I+1, Maxint);
  2269. I := ConstPos('|', Z); { check for a 'default' data }
  2270. if I = 0 then
  2271. I := Length(Z)+1;
  2272. Default := Copy(Z, I+1, Maxint);
  2273. SetLength(Z, I-1);
  2274. I := ConstPos(',', Z); { comma separates subkey and value }
  2275. if I <> 0 then begin
  2276. Subkey := Copy(Z, 1, I-1);
  2277. Value := Copy(Z, I+1, Maxint);
  2278. if ConvertConstPercentStr(Subkey) and ConvertConstPercentStr(Value) and
  2279. ConvertConstPercentStr(Default) then begin
  2280. CheckConst(Subkey, MinVersion, AllowedConsts);
  2281. CheckConst(Value, MinVersion, AllowedConsts);
  2282. CheckConst(Default, MinVersion, AllowedConsts);
  2283. Result := True;
  2284. Exit;
  2285. end;
  2286. end;
  2287. end;
  2288. end;
  2289. end;
  2290. { it will only reach here if there was a parsing error }
  2291. Result := False;
  2292. end;
  2293. function CheckIniConst(C: String): Boolean;
  2294. { based on ExpandIniConst in Main.pas }
  2295. var
  2296. Z, Filename, Section, Key, Default: String;
  2297. I: Integer;
  2298. begin
  2299. Delete(C, 1, 4); { skip past 'ini:' }
  2300. I := ConstPos(',', C);
  2301. if I <> 0 then begin
  2302. Z := Copy(C, 1, I-1);
  2303. if Z <> '' then begin
  2304. Filename := Z;
  2305. Z := Copy(C, I+1, Maxint);
  2306. I := ConstPos('|', Z); { check for a 'default' data }
  2307. if I = 0 then
  2308. I := Length(Z)+1;
  2309. Default := Copy(Z, I+1, Maxint);
  2310. SetLength(Z, I-1);
  2311. I := ConstPos(',', Z); { comma separates section and key }
  2312. if I <> 0 then begin
  2313. Section := Copy(Z, 1, I-1);
  2314. Key := Copy(Z, I+1, Maxint);
  2315. if ConvertConstPercentStr(Filename) and ConvertConstPercentStr(Section) and
  2316. ConvertConstPercentStr(Key) and ConvertConstPercentStr(Default) then begin
  2317. CheckConst(Filename, MinVersion, AllowedConsts);
  2318. CheckConst(Section, MinVersion, AllowedConsts);
  2319. CheckConst(Key, MinVersion, AllowedConsts);
  2320. CheckConst(Default, MinVersion, AllowedConsts);
  2321. Result := True;
  2322. Exit;
  2323. end;
  2324. end;
  2325. end;
  2326. end;
  2327. { it will only reach here if there was a parsing error }
  2328. Result := False;
  2329. end;
  2330. function CheckParamConst(C: String): Boolean;
  2331. var
  2332. Z, Param, Default: String;
  2333. I: Integer;
  2334. begin
  2335. Delete(C, 1, 6); { skip past 'param:' }
  2336. Z := C;
  2337. I := ConstPos('|', Z); { check for a 'default' data }
  2338. if I = 0 then
  2339. I := Length(Z)+1;
  2340. Default := Copy(Z, I+1, Maxint);
  2341. SetLength(Z, I-1);
  2342. Param := Z;
  2343. if ConvertConstPercentStr(Param) and ConvertConstPercentStr(Default) then begin
  2344. CheckConst(Param, MinVersion, AllowedConsts);
  2345. CheckConst(Default, MinVersion, AllowedConsts);
  2346. Result := True;
  2347. Exit;
  2348. end;
  2349. { it will only reach here if there was a parsing error }
  2350. Result := False;
  2351. end;
  2352. function CheckCodeConst(C: String): Boolean;
  2353. var
  2354. Z, ScriptFunc, Param: String;
  2355. I: Integer;
  2356. begin
  2357. Delete(C, 1, 5); { skip past 'code:' }
  2358. Z := C;
  2359. I := ConstPos('|', Z); { check for optional parameter }
  2360. if I = 0 then
  2361. I := Length(Z)+1;
  2362. Param := Copy(Z, I+1, Maxint);
  2363. SetLength(Z, I-1);
  2364. ScriptFunc := Z;
  2365. if ConvertConstPercentStr(ScriptFunc) and ConvertConstPercentStr(Param) then begin
  2366. CheckConst(Param, MinVersion, AllowedConsts);
  2367. CodeCompiler.AddExport(ScriptFunc, 'String @String', False, True, LineFileName, LineNumber);
  2368. Result := True;
  2369. Exit;
  2370. end;
  2371. { it will only reach here if there was a parsing error }
  2372. Result := False;
  2373. end;
  2374. function CheckDriveConst(C: String): Boolean;
  2375. begin
  2376. Delete(C, 1, 6); { skip past 'drive:' }
  2377. if ConvertConstPercentStr(C) then begin
  2378. CheckConst(C, MinVersion, AllowedConsts);
  2379. Result := True;
  2380. Exit;
  2381. end;
  2382. { it will only reach here if there was a parsing error }
  2383. Result := False;
  2384. end;
  2385. function CheckCustomMessageConst(C: String): Boolean;
  2386. var
  2387. MsgName, Arg: String;
  2388. I, ArgCount: Integer;
  2389. Found: Boolean;
  2390. LineInfo: TLineInfo;
  2391. begin
  2392. Delete(C, 1, 3); { skip past 'cm:' }
  2393. I := ConstPos(',', C);
  2394. if I = 0 then
  2395. MsgName := C
  2396. else
  2397. MsgName := Copy(C, 1, I-1);
  2398. { Check each argument }
  2399. ArgCount := 0;
  2400. while I > 0 do begin
  2401. if ArgCount >= 9 then begin
  2402. { Can't have more than 9 arguments (%1 through %9) }
  2403. Result := False;
  2404. Exit;
  2405. end;
  2406. Delete(C, 1, I);
  2407. I := ConstPos(',', C);
  2408. if I = 0 then
  2409. Arg := C
  2410. else
  2411. Arg := Copy(C, 1, I-1);
  2412. if not ConvertConstPercentStr(Arg) then begin
  2413. Result := False;
  2414. Exit;
  2415. end;
  2416. CheckConst(Arg, MinVersion, AllowedConsts);
  2417. Inc(ArgCount);
  2418. end;
  2419. Found := False;
  2420. for I := 0 to ExpectedCustomMessageNames.Count-1 do begin
  2421. if CompareText(ExpectedCustomMessageNames[I], MsgName) = 0 then begin
  2422. Found := True;
  2423. Break;
  2424. end;
  2425. end;
  2426. if not Found then begin
  2427. LineInfo := TLineInfo.Create;
  2428. LineInfo.FileName := LineFileName;
  2429. LineInfo.FileLineNumber := LineNumber;
  2430. ExpectedCustomMessageNames.AddObject(MsgName, LineInfo);
  2431. end;
  2432. Result := True;
  2433. end;
  2434. const
  2435. UserConsts: array[0..0] of String = (
  2436. 'username');
  2437. Consts: array[0..42] of String = (
  2438. 'src', 'srcexe', 'tmp', 'app', 'win', 'sys', 'sd', 'groupname', 'commonfonts', 'hwnd',
  2439. 'commonpf', 'commonpf32', 'commonpf64', 'commoncf', 'commoncf32', 'commoncf64',
  2440. 'autopf', 'autopf32', 'autopf64', 'autocf', 'autocf32', 'autocf64',
  2441. 'computername', 'dao', 'cmd', 'wizardhwnd', 'sysuserinfoname', 'sysuserinfoorg',
  2442. 'userinfoname', 'userinfoorg', 'userinfoserial', 'uninstallexe',
  2443. 'language', 'syswow64', 'sysnative', 'log', 'dotnet11', 'dotnet20', 'dotnet2032',
  2444. 'dotnet2064', 'dotnet40', 'dotnet4032', 'dotnet4064');
  2445. UserShellFolderConsts: array[0..13] of String = (
  2446. 'userdesktop', 'userstartmenu', 'userprograms', 'userstartup',
  2447. 'userappdata', 'userdocs', 'usertemplates', 'userfavorites', 'usersendto', 'userfonts',
  2448. 'localappdata', 'userpf', 'usercf', 'usersavedgames');
  2449. ShellFolderConsts: array[0..16] of String = (
  2450. 'group', 'commondesktop', 'commonstartmenu', 'commonprograms', 'commonstartup',
  2451. 'commonappdata', 'commondocs', 'commontemplates',
  2452. 'autodesktop', 'autostartmenu', 'autoprograms', 'autostartup',
  2453. 'autoappdata', 'autodocs', 'autotemplates', 'autofavorites', 'autofonts');
  2454. AllowedConstsNames: array[TAllowedConst] of String = (
  2455. 'olddata', 'break');
  2456. var
  2457. I, Start, K: Integer;
  2458. C: TAllowedConst;
  2459. Cnst: String;
  2460. label 1;
  2461. begin
  2462. Result := False;
  2463. I := 1;
  2464. while I <= Length(S) do begin
  2465. if S[I] = '{' then begin
  2466. if (I < Length(S)) and (S[I+1] = '{') then
  2467. Inc(I)
  2468. else begin
  2469. Result := True;
  2470. Start := I;
  2471. { Find the closing brace, skipping over any embedded constants }
  2472. I := SkipPastConst(S, I);
  2473. if I = 0 then { unclosed constant? }
  2474. AbortCompileOnLineFmt(SCompilerUnterminatedConst, [Copy(S, Start+1, Maxint)]);
  2475. Dec(I); { 'I' now points to the closing brace }
  2476. { Now check the constant }
  2477. Cnst := Copy(S, Start+1, I-(Start+1));
  2478. if Cnst <> '' then begin
  2479. HandleRenamedConstants(Cnst, RenamedConstantCallback);
  2480. if Cnst = '\' then
  2481. goto 1;
  2482. if Cnst[1] = '%' then begin
  2483. if not CheckEnvConst(Cnst) then
  2484. AbortCompileOnLineFmt(SCompilerBadEnvConst, [Cnst]);
  2485. goto 1;
  2486. end;
  2487. if Copy(Cnst, 1, 4) = 'reg:' then begin
  2488. if not CheckRegConst(Cnst) then
  2489. AbortCompileOnLineFmt(SCompilerBadRegConst, [Cnst]);
  2490. goto 1;
  2491. end;
  2492. if Copy(Cnst, 1, 4) = 'ini:' then begin
  2493. if not CheckIniConst(Cnst) then
  2494. AbortCompileOnLineFmt(SCompilerBadIniConst, [Cnst]);
  2495. goto 1;
  2496. end;
  2497. if Copy(Cnst, 1, 6) = 'param:' then begin
  2498. if not CheckParamConst(Cnst) then
  2499. AbortCompileOnLineFmt(SCompilerBadParamConst, [Cnst]);
  2500. goto 1;
  2501. end;
  2502. if Copy(Cnst, 1, 5) = 'code:' then begin
  2503. if not CheckCodeConst(Cnst) then
  2504. AbortCompileOnLineFmt(SCompilerBadCodeConst, [Cnst]);
  2505. goto 1;
  2506. end;
  2507. if Copy(Cnst, 1, 6) = 'drive:' then begin
  2508. if not CheckDriveConst(Cnst) then
  2509. AbortCompileOnLineFmt(SCompilerBadDriveConst, [Cnst]);
  2510. goto 1;
  2511. end;
  2512. if Copy(Cnst, 1, 3) = 'cm:' then begin
  2513. if not CheckCustomMessageConst(Cnst) then
  2514. AbortCompileOnLineFmt(SCompilerBadCustomMessageConst, [Cnst]);
  2515. goto 1;
  2516. end;
  2517. for K := Low(UserConsts) to High(UserConsts) do
  2518. if Cnst = UserConsts[K] then begin
  2519. UsedUserAreas.Add(Cnst);
  2520. goto 1;
  2521. end;
  2522. for K := Low(Consts) to High(Consts) do
  2523. if Cnst = Consts[K] then
  2524. goto 1;
  2525. for K := Low(UserShellFolderConsts) to High(UserShellFolderConsts) do
  2526. if Cnst = UserShellFolderConsts[K] then begin
  2527. UsedUserAreas.Add(Cnst);
  2528. goto 1;
  2529. end;
  2530. for K := Low(ShellFolderConsts) to High(ShellFolderConsts) do
  2531. if Cnst = ShellFolderConsts[K] then
  2532. goto 1;
  2533. for C := Low(C) to High(C) do
  2534. if Cnst = AllowedConstsNames[C] then begin
  2535. if not(C in AllowedConsts) then
  2536. AbortCompileOnLineFmt(SCompilerConstCannotUse, [Cnst]);
  2537. goto 1;
  2538. end;
  2539. end;
  2540. AbortCompileOnLineFmt(SCompilerUnknownConst, [Cnst]);
  2541. 1:{ Constant is OK }
  2542. end;
  2543. end;
  2544. Inc(I);
  2545. end;
  2546. end;
  2547. function TSetupCompiler.EvalCheckOrInstallIdentifier(Sender: TSimpleExpression;
  2548. const Name: String; const Parameters: array of const): Boolean;
  2549. var
  2550. IsCheck: Boolean;
  2551. Decl: String;
  2552. I: Integer;
  2553. begin
  2554. IsCheck := Boolean(Sender.Tag);
  2555. if IsCheck then
  2556. Decl := 'Boolean'
  2557. else
  2558. Decl := '0';
  2559. for I := Low(Parameters) to High(Parameters) do begin
  2560. if Parameters[I].VType = vtUnicodeString then
  2561. Decl := Decl + ' @String'
  2562. else if Parameters[I].VType = vtInteger then
  2563. Decl := Decl + ' @LongInt'
  2564. else if Parameters[I].VType = vtBoolean then
  2565. Decl := Decl + ' @Boolean'
  2566. else
  2567. raise Exception.Create('Internal Error: unknown parameter type');
  2568. end;
  2569. CodeCompiler.AddExport(Name, Decl, False, True, LineFileName, LineNumber);
  2570. Result := True; { Result doesn't matter }
  2571. end;
  2572. procedure TSetupCompiler.CheckCheckOrInstall(const ParamName, ParamData: String;
  2573. const Kind: TCheckOrInstallKind);
  2574. var
  2575. SimpleExpression: TSimpleExpression;
  2576. IsCheck, BoolResult: Boolean;
  2577. begin
  2578. if ParamData <> '' then begin
  2579. if (Kind <> cikDirectiveCheck) or not TryStrToBoolean(ParamData, BoolResult) then begin
  2580. IsCheck := Kind in [cikCheck, cikDirectiveCheck];
  2581. { Check the expression in ParamData and add exports while
  2582. evaluating. Use Lazy checking to make sure everything is evaluated. }
  2583. try
  2584. SimpleExpression := TSimpleExpression.Create;
  2585. try
  2586. SimpleExpression.Lazy := False;
  2587. SimpleExpression.Expression := ParamData;
  2588. SimpleExpression.OnEvalIdentifier := EvalCheckOrInstallIdentifier;
  2589. SimpleExpression.SilentOrAllowed := False;
  2590. SimpleExpression.SingleIdentifierMode := not IsCheck;
  2591. SimpleExpression.ParametersAllowed := True;
  2592. SimpleExpression.Tag := Integer(IsCheck);
  2593. SimpleExpression.Eval;
  2594. finally
  2595. SimpleExpression.Free;
  2596. end;
  2597. except
  2598. AbortCompileOnLineFmt(SCompilerExpressionError, [ParamName,
  2599. GetExceptMessage]);
  2600. end;
  2601. end;
  2602. end
  2603. else begin
  2604. if Kind = cikDirectiveCheck then
  2605. AbortCompileOnLineFmt(SCompilerEntryInvalid2, ['Setup', ParamName]);
  2606. end;
  2607. end;
  2608. function ExtractFlag(var S: String; const FlagStrs: array of PChar): Integer;
  2609. var
  2610. I: Integer;
  2611. F: String;
  2612. begin
  2613. F := ExtractStr(S, ' ');
  2614. if F = '' then begin
  2615. Result := -2;
  2616. Exit;
  2617. end;
  2618. Result := -1;
  2619. for I := 0 to High(FlagStrs) do
  2620. if StrIComp(FlagStrs[I], PChar(F)) = 0 then begin
  2621. Result := I;
  2622. Break;
  2623. end;
  2624. end;
  2625. function ExtractType(var S: String; const TypeEntries: TList): Integer;
  2626. var
  2627. I: Integer;
  2628. F: String;
  2629. begin
  2630. F := ExtractStr(S, ' ');
  2631. if F = '' then begin
  2632. Result := -2;
  2633. Exit;
  2634. end;
  2635. Result := -1;
  2636. if TypeEntries.Count <> 0 then begin
  2637. for I := 0 to TypeEntries.Count-1 do
  2638. if CompareText(PSetupTypeEntry(TypeEntries[I]).Name, F) = 0 then begin
  2639. Result := I;
  2640. Break;
  2641. end;
  2642. end else begin
  2643. for I := 0 to High(DefaultTypeEntryNames) do
  2644. if StrIComp(DefaultTypeEntryNames[I], PChar(F)) = 0 then begin
  2645. Result := I;
  2646. Break;
  2647. end;
  2648. end;
  2649. end;
  2650. function ExtractLangIndex(SetupCompiler: TSetupCompiler; var S: String;
  2651. const LanguageEntryIndex: Integer; const Pre: Boolean): Integer;
  2652. var
  2653. I: Integer;
  2654. begin
  2655. if LanguageEntryIndex = -1 then begin
  2656. { Message in the main script }
  2657. I := Pos('.', S);
  2658. if I = 0 then begin
  2659. { No '.'; apply to all languages }
  2660. Result := -1;
  2661. end
  2662. else begin
  2663. { Apply to specified language }
  2664. Result := SetupCompiler.FindLangEntryIndexByName(Copy(S, 1, I-1), Pre);
  2665. S := Copy(S, I+1, Maxint);
  2666. end;
  2667. end
  2668. else begin
  2669. { Inside a language file }
  2670. if Pos('.', S) <> 0 then
  2671. SetupCompiler.AbortCompileOnLine(SCompilerCantSpecifyLanguage);
  2672. Result := LanguageEntryIndex;
  2673. end;
  2674. end;
  2675. procedure AddToCommaText(var CommaText: String; const S: String);
  2676. begin
  2677. if CommaText <> '' then
  2678. CommaText := CommaText + ',';
  2679. CommaText := CommaText + S;
  2680. end;
  2681. function TSetupCompiler.EvalComponentIdentifier(Sender: TSimpleExpression; const Name: String;
  2682. const Parameters: array of const): Boolean;
  2683. var
  2684. Found: Boolean;
  2685. ComponentEntry: PSetupComponentEntry;
  2686. I: Integer;
  2687. begin
  2688. Found := False;
  2689. for I := 0 to ComponentEntries.Count-1 do begin
  2690. ComponentEntry := PSetupComponentEntry(ComponentEntries[I]);
  2691. if CompareText(ComponentEntry.Name, Name) = 0 then begin
  2692. ComponentEntry.Used := True;
  2693. Found := True;
  2694. { Don't Break; there may be multiple components with the same name }
  2695. end;
  2696. end;
  2697. if not Found then
  2698. raise Exception.CreateFmt(SCompilerParamUnknownComponent, [ParamCommonComponents]);
  2699. Result := True; { Result doesn't matter }
  2700. end;
  2701. function TSetupCompiler.EvalTaskIdentifier(Sender: TSimpleExpression; const Name: String;
  2702. const Parameters: array of const): Boolean;
  2703. var
  2704. Found: Boolean;
  2705. TaskEntry: PSetupTaskEntry;
  2706. I: Integer;
  2707. begin
  2708. Found := False;
  2709. for I := 0 to TaskEntries.Count-1 do begin
  2710. TaskEntry := PSetupTaskEntry(TaskEntries[I]);
  2711. if CompareText(TaskEntry.Name, Name) = 0 then begin
  2712. TaskEntry.Used := True;
  2713. Found := True;
  2714. { Don't Break; there may be multiple tasks with the same name }
  2715. end;
  2716. end;
  2717. if not Found then
  2718. raise Exception.CreateFmt(SCompilerParamUnknownTask, [ParamCommonTasks]);
  2719. Result := True; { Result doesn't matter }
  2720. end;
  2721. function TSetupCompiler.EvalLanguageIdentifier(Sender: TSimpleExpression; const Name: String;
  2722. const Parameters: array of const): Boolean;
  2723. var
  2724. LanguageEntry: PSetupLanguageEntry;
  2725. I: Integer;
  2726. begin
  2727. for I := 0 to LanguageEntries.Count-1 do begin
  2728. LanguageEntry := PSetupLanguageEntry(LanguageEntries[I]);
  2729. if CompareText(LanguageEntry.Name, Name) = 0 then begin
  2730. Result := True; { Result doesn't matter }
  2731. Exit;
  2732. end;
  2733. end;
  2734. raise Exception.CreateFmt(SCompilerParamUnknownLanguage, [ParamCommonLanguages]);
  2735. end;
  2736. procedure TSetupCompiler.ProcessExpressionParameter(const ParamName,
  2737. ParamData: String; OnEvalIdentifier: TSimpleExpressionOnEvalIdentifier;
  2738. SlashConvert: Boolean; var ProcessedParamData: String);
  2739. var
  2740. SimpleExpression: TSimpleExpression;
  2741. begin
  2742. ProcessedParamData := ParamData;
  2743. if ProcessedParamData <> '' then begin
  2744. if SlashConvert then
  2745. StringChange(ProcessedParamData, '/', '\');
  2746. { Check the expression in ParamData and set the Used properties while
  2747. evaluating. Use non-Lazy checking to make sure everything is evaluated. }
  2748. try
  2749. SimpleExpression := TSimpleExpression.Create;
  2750. try
  2751. SimpleExpression.Lazy := False;
  2752. SimpleExpression.Expression := ProcessedParamData;
  2753. SimpleExpression.OnEvalIdentifier := OnEvalIdentifier;
  2754. SimpleExpression.SilentOrAllowed := True;
  2755. SimpleExpression.SingleIdentifierMode := False;
  2756. SimpleExpression.ParametersAllowed := False;
  2757. SimpleExpression.Eval;
  2758. finally
  2759. SimpleExpression.Free;
  2760. end;
  2761. except
  2762. AbortCompileOnLineFmt(SCompilerExpressionError, [ParamName,
  2763. GetExceptMessage]);
  2764. end;
  2765. end;
  2766. end;
  2767. procedure TSetupCompiler.ProcessWildcardsParameter(const ParamData: String;
  2768. const AWildcards: TStringList; const TooLongMsg: String);
  2769. var
  2770. S, AWildcard: String;
  2771. begin
  2772. S := PathLowercase(ParamData);
  2773. while True do begin
  2774. AWildcard := ExtractStr(S, ',');
  2775. if AWildcard = '' then
  2776. Break;
  2777. { Impose a reasonable limit on the length of the string so
  2778. that WildcardMatch can't overflow the stack }
  2779. if Length(AWildcard) >= MAX_PATH then
  2780. AbortCompileOnLine(TooLongMsg);
  2781. AWildcards.Add(AWildcard);
  2782. end;
  2783. end;
  2784. procedure TSetupCompiler.ProcessMinVersionParameter(const ParamValue: TParamValue;
  2785. var AMinVersion: TSetupVersionData);
  2786. begin
  2787. if ParamValue.Found then
  2788. if not StrToSetupVersionData(ParamValue.Data, AMinVersion) then
  2789. AbortCompileParamError(SCompilerParamInvalid2, ParamCommonMinVersion);
  2790. end;
  2791. procedure TSetupCompiler.ProcessOnlyBelowVersionParameter(const ParamValue: TParamValue;
  2792. var AOnlyBelowVersion: TSetupVersionData);
  2793. begin
  2794. if ParamValue.Found then
  2795. if not StrToSetupVersionData(ParamValue.Data, AOnlyBelowVersion) then
  2796. AbortCompileParamError(SCompilerParamInvalid2, ParamCommonOnlyBelowVersion);
  2797. end;
  2798. procedure TSetupCompiler.ProcessPermissionsParameter(ParamData: String;
  2799. const AccessMasks: array of TNameAndAccessMask; var PermissionsEntry: Smallint);
  2800. procedure GetSidFromName(const AName: String; var ASid: TGrantPermissionSid);
  2801. type
  2802. TKnownSid = record
  2803. Name: String;
  2804. Sid: TGrantPermissionSid;
  2805. end;
  2806. const
  2807. SECURITY_WORLD_SID_AUTHORITY = 1;
  2808. SECURITY_WORLD_RID = $00000000;
  2809. SECURITY_CREATOR_SID_AUTHORITY = 3;
  2810. SECURITY_CREATOR_OWNER_RID = $00000000;
  2811. SECURITY_NT_AUTHORITY = 5;
  2812. SECURITY_AUTHENTICATED_USER_RID = $0000000B;
  2813. SECURITY_LOCAL_SYSTEM_RID = $00000012;
  2814. SECURITY_LOCAL_SERVICE_RID = $00000013;
  2815. SECURITY_NETWORK_SERVICE_RID = $00000014;
  2816. SECURITY_BUILTIN_DOMAIN_RID = $00000020;
  2817. DOMAIN_ALIAS_RID_ADMINS = $00000220;
  2818. DOMAIN_ALIAS_RID_USERS = $00000221;
  2819. DOMAIN_ALIAS_RID_GUESTS = $00000222;
  2820. DOMAIN_ALIAS_RID_POWER_USERS = $00000223;
  2821. DOMAIN_ALIAS_RID_IIS_IUSRS = $00000238;
  2822. KnownSids: array[0..10] of TKnownSid = (
  2823. (Name: 'admins';
  2824. Sid: (Authority: (Value: (0, 0, 0, 0, 0, SECURITY_NT_AUTHORITY));
  2825. SubAuthCount: 2;
  2826. SubAuth: (SECURITY_BUILTIN_DOMAIN_RID, DOMAIN_ALIAS_RID_ADMINS))),
  2827. (Name: 'authusers';
  2828. Sid: (Authority: (Value: (0, 0, 0, 0, 0, SECURITY_NT_AUTHORITY));
  2829. SubAuthCount: 1;
  2830. SubAuth: (SECURITY_AUTHENTICATED_USER_RID, 0))),
  2831. (Name: 'creatorowner';
  2832. Sid: (Authority: (Value: (0, 0, 0, 0, 0, SECURITY_CREATOR_SID_AUTHORITY));
  2833. SubAuthCount: 1;
  2834. SubAuth: (SECURITY_CREATOR_OWNER_RID, 0))),
  2835. (Name: 'everyone';
  2836. Sid: (Authority: (Value: (0, 0, 0, 0, 0, SECURITY_WORLD_SID_AUTHORITY));
  2837. SubAuthCount: 1;
  2838. SubAuth: (SECURITY_WORLD_RID, 0))),
  2839. (Name: 'guests';
  2840. Sid: (Authority: (Value: (0, 0, 0, 0, 0, SECURITY_NT_AUTHORITY));
  2841. SubAuthCount: 2;
  2842. SubAuth: (SECURITY_BUILTIN_DOMAIN_RID, DOMAIN_ALIAS_RID_GUESTS))),
  2843. (Name: 'iisiusrs';
  2844. Sid: (Authority: (Value: (0, 0, 0, 0, 0, SECURITY_NT_AUTHORITY));
  2845. SubAuthCount: 2;
  2846. SubAuth: (SECURITY_BUILTIN_DOMAIN_RID, DOMAIN_ALIAS_RID_IIS_IUSRS))),
  2847. (Name: 'networkservice';
  2848. Sid: (Authority: (Value: (0, 0, 0, 0, 0, SECURITY_NT_AUTHORITY));
  2849. SubAuthCount: 1;
  2850. SubAuth: (SECURITY_NETWORK_SERVICE_RID, 0))),
  2851. (Name: 'powerusers';
  2852. Sid: (Authority: (Value: (0, 0, 0, 0, 0, SECURITY_NT_AUTHORITY));
  2853. SubAuthCount: 2;
  2854. SubAuth: (SECURITY_BUILTIN_DOMAIN_RID, DOMAIN_ALIAS_RID_POWER_USERS))),
  2855. (Name: 'service';
  2856. Sid: (Authority: (Value: (0, 0, 0, 0, 0, SECURITY_NT_AUTHORITY));
  2857. SubAuthCount: 1;
  2858. SubAuth: (SECURITY_LOCAL_SERVICE_RID, 0))),
  2859. (Name: 'system';
  2860. Sid: (Authority: (Value: (0, 0, 0, 0, 0, SECURITY_NT_AUTHORITY));
  2861. SubAuthCount: 1;
  2862. SubAuth: (SECURITY_LOCAL_SYSTEM_RID, 0))),
  2863. (Name: 'users';
  2864. Sid: (Authority: (Value: (0, 0, 0, 0, 0, SECURITY_NT_AUTHORITY));
  2865. SubAuthCount: 2;
  2866. SubAuth: (SECURITY_BUILTIN_DOMAIN_RID, DOMAIN_ALIAS_RID_USERS)))
  2867. );
  2868. var
  2869. I: Integer;
  2870. begin
  2871. for I := Low(KnownSids) to High(KnownSids) do
  2872. if CompareText(AName, KnownSids[I].Name) = 0 then begin
  2873. ASid := KnownSids[I].Sid;
  2874. Exit;
  2875. end;
  2876. AbortCompileOnLineFmt(SCompilerPermissionsUnknownSid, [AName]);
  2877. end;
  2878. procedure GetAccessMaskFromName(const AName: String; var AAccessMask: DWORD);
  2879. var
  2880. I: Integer;
  2881. begin
  2882. for I := Low(AccessMasks) to High(AccessMasks) do
  2883. if CompareText(AName, AccessMasks[I].Name) = 0 then begin
  2884. AAccessMask := AccessMasks[I].Mask;
  2885. Exit;
  2886. end;
  2887. AbortCompileOnLineFmt(SCompilerPermissionsUnknownMask, [AName]);
  2888. end;
  2889. var
  2890. Perms, E: AnsiString;
  2891. S: String;
  2892. PermsCount, P, I: Integer;
  2893. Entry: TGrantPermissionEntry;
  2894. NewPermissionEntry: PSetupPermissionEntry;
  2895. begin
  2896. { Parse }
  2897. PermsCount := 0;
  2898. while True do begin
  2899. S := ExtractStr(ParamData, ' ');
  2900. if S = '' then
  2901. Break;
  2902. P := Pos('-', S);
  2903. if P = 0 then
  2904. AbortCompileOnLineFmt(SCompilerPermissionsInvalidValue, [S]);
  2905. FillChar(Entry, SizeOf(Entry), 0);
  2906. GetSidFromName(Copy(S, 1, P-1), Entry.Sid);
  2907. GetAccessMaskFromName(Copy(S, P+1, Maxint), Entry.AccessMask);
  2908. SetString(E, PAnsiChar(@Entry), SizeOf(Entry));
  2909. Perms := Perms + E;
  2910. Inc(PermsCount);
  2911. if PermsCount > MaxGrantPermissionEntries then
  2912. AbortCompileOnLineFmt(SCompilerPermissionsValueLimitExceeded, [MaxGrantPermissionEntries]);
  2913. end;
  2914. if Perms = '' then begin
  2915. { No permissions }
  2916. PermissionsEntry := -1;
  2917. end
  2918. else begin
  2919. { See if there's already an identical permissions entry }
  2920. for I := 0 to PermissionEntries.Count-1 do
  2921. if PSetupPermissionEntry(PermissionEntries[I]).Permissions = Perms then begin
  2922. PermissionsEntry := I;
  2923. Exit;
  2924. end;
  2925. { If not, create a new one }
  2926. PermissionEntries.Expand;
  2927. NewPermissionEntry := AllocMem(SizeOf(NewPermissionEntry^));
  2928. NewPermissionEntry.Permissions := Perms;
  2929. I := PermissionEntries.Add(NewPermissionEntry);
  2930. if I > High(PermissionsEntry) then
  2931. AbortCompileOnLine(SCompilerPermissionsTooMany);
  2932. PermissionsEntry := I;
  2933. end;
  2934. end;
  2935. procedure TSetupCompiler.ReadTextFile(const Filename: String; const LangIndex: Integer;
  2936. var Text: AnsiString);
  2937. var
  2938. F: TFile;
  2939. Size: Cardinal;
  2940. UnicodeFile, RTFFile: Boolean;
  2941. AnsiConvertCodePage: Integer;
  2942. S: RawByteString;
  2943. U: String;
  2944. begin
  2945. try
  2946. F := TFile.Create(Filename, fdOpenExisting, faRead, fsRead);
  2947. try
  2948. Size := F.Size.Lo;
  2949. SetLength(S, Size);
  2950. F.ReadBuffer(S[1], Size);
  2951. UnicodeFile := ((Size >= 2) and (PWord(Pointer(S))^ = $FEFF)) or
  2952. ((Size >= 3) and (S[1] = #$EF) and (S[2] = #$BB) and (S[3] = #$BF));
  2953. RTFFile := Copy(S, 1, 6) = '{\rtf1';
  2954. if not UnicodeFile and not RTFFile and IsUTF8String(S) then begin
  2955. S := #$EF + #$BB + #$BF + S;
  2956. UnicodeFile := True;
  2957. end;
  2958. if not UnicodeFile and not RTFFile and (LangIndex >= 0) then begin
  2959. AnsiConvertCodePage := TPreLangData(PreLangDataList[LangIndex]).LanguageCodePage;
  2960. if AnsiConvertCodePage <> 0 then begin
  2961. AddStatus(Format(SCompilerStatusConvertCodePage , [AnsiConvertCodePage]));
  2962. { Convert the ANSI text to Unicode. }
  2963. SetCodePage(S, AnsiConvertCodePage, False);
  2964. U := String(S);
  2965. { Store the Unicode text in Text with a UTF16 BOM. }
  2966. Size := Length(U)*SizeOf(U[1]);
  2967. SetLength(Text, Size+2);
  2968. PWord(Pointer(Text))^ := $FEFF;
  2969. Move(U[1], Text[3], Size);
  2970. end else
  2971. Text := S;
  2972. end else
  2973. Text := S;
  2974. finally
  2975. F.Free;
  2976. end;
  2977. except
  2978. raise Exception.CreateFmt(SCompilerReadError, [Filename, GetExceptMessage]);
  2979. end;
  2980. end;
  2981. procedure TSetupCompiler.SeparateDirective(const Line: PChar;
  2982. var Key, Value: String);
  2983. var
  2984. P: PChar;
  2985. begin
  2986. Key := '';
  2987. Value := '';
  2988. P := Line;
  2989. SkipWhitespace(P);
  2990. if P^ <> #0 then begin
  2991. Key := ExtractWords(P, '=');
  2992. if Key = '' then
  2993. AbortCompileOnLine(SCompilerDirectiveNameMissing);
  2994. if P^ <> '=' then
  2995. AbortCompileOnLineFmt(SCompilerDirectiveHasNoValue, [Key]);
  2996. Inc(P);
  2997. SkipWhitespace(P);
  2998. Value := ExtractWords(P, #0);
  2999. { If Value is surrounded in quotes, remove them. Note that unlike parameter
  3000. values, for backward compatibility we don't require embedded quotes to be
  3001. doubled, nor do we require surrounding quotes when there's a quote in
  3002. the middle of the value. }
  3003. if (Length(Value) >= 2) and
  3004. (Value[1] = '"') and (Value[Length(Value)] = '"') then
  3005. Value := Copy(Value, 2, Length(Value)-2);
  3006. end;
  3007. end;
  3008. procedure TSetupCompiler.EnumSetupProc(const Line: PChar; const Ext: Integer);
  3009. var
  3010. KeyName, Value: String;
  3011. I: Integer;
  3012. Directive: TSetupSectionDirective;
  3013. procedure Invalid;
  3014. begin
  3015. AbortCompileOnLineFmt(SCompilerEntryInvalid2, ['Setup', KeyName]);
  3016. end;
  3017. function StrToBool(const S: String): Boolean;
  3018. begin
  3019. Result := False;
  3020. if not TryStrToBoolean(S, Result) then
  3021. Invalid;
  3022. end;
  3023. function StrToIntRange(const S: String; const AMin, AMax: Integer): Integer;
  3024. var
  3025. E: Integer;
  3026. begin
  3027. Val(S, Result, E);
  3028. if (E <> 0) or (Result < AMin) or (Result > AMax) then
  3029. Invalid;
  3030. end;
  3031. procedure SetSetupHeaderOption(const Option: TSetupHeaderOption);
  3032. begin
  3033. if not StrToBool(Value) then
  3034. Exclude(SetupHeader.Options, Option)
  3035. else
  3036. Include(SetupHeader.Options, Option);
  3037. end;
  3038. function ExtractNumber(var P: PChar): Integer;
  3039. var
  3040. I: Integer;
  3041. begin
  3042. Result := 0;
  3043. for I := 0 to 3 do begin { maximum of 4 digits }
  3044. if not CharInSet(P^, ['0'..'9']) then begin
  3045. if I = 0 then
  3046. Invalid;
  3047. Break;
  3048. end;
  3049. Result := (Result * 10) + (Ord(P^) - Ord('0'));
  3050. Inc(P);
  3051. end;
  3052. end;
  3053. procedure GeneratePasswordHashAndSalt(const Password: String;
  3054. var Hash: TSHA1Digest; var Salt: TSetupSalt);
  3055. var
  3056. Context: TSHA1Context;
  3057. begin
  3058. { Random salt is mixed into the password hash to make it more difficult
  3059. for someone to tell that two installations use the same password. A
  3060. fixed string is also mixed in "just in case" the system's RNG is
  3061. broken -- this hash must never be the same as the hash used for
  3062. encryption. }
  3063. GenerateRandomBytes(Salt, SizeOf(Salt));
  3064. SHA1Init(Context);
  3065. SHA1Update(Context, PAnsiChar('PasswordCheckHash')^, Length('PasswordCheckHash'));
  3066. SHA1Update(Context, Salt, SizeOf(Salt));
  3067. SHA1Update(Context, Pointer(Password)^, Length(Password)*SizeOf(Password[1]));
  3068. Hash := SHA1Final(Context);
  3069. end;
  3070. procedure StrToTouchDate(const S: String);
  3071. var
  3072. P: PChar;
  3073. Year, Month, Day: Integer;
  3074. ST: TSystemTime;
  3075. FT: TFileTime;
  3076. begin
  3077. if CompareText(S, 'current') = 0 then begin
  3078. TouchDateOption := tdCurrent;
  3079. Exit;
  3080. end;
  3081. if CompareText(S, 'none') = 0 then begin
  3082. TouchDateOption := tdNone;
  3083. Exit;
  3084. end;
  3085. P := PChar(S);
  3086. Year := ExtractNumber(P);
  3087. if (Year < 1980) or (Year > 2107) or (P^ <> '-') then
  3088. Invalid;
  3089. Inc(P);
  3090. Month := ExtractNumber(P);
  3091. if (Month < 1) or (Month > 12) or (P^ <> '-') then
  3092. Invalid;
  3093. Inc(P);
  3094. Day := ExtractNumber(P);
  3095. if (Day < 1) or (Day > 31) or (P^ <> #0) then
  3096. Invalid;
  3097. { Verify that the day is valid for the specified month & year }
  3098. FillChar(ST, SizeOf(ST), 0);
  3099. ST.wYear := Year;
  3100. ST.wMonth := Month;
  3101. ST.wDay := Day;
  3102. if not SystemTimeToFileTime(ST, FT) then
  3103. Invalid;
  3104. TouchDateOption := tdExplicit;
  3105. TouchDateYear := Year;
  3106. TouchDateMonth := Month;
  3107. TouchDateDay := Day;
  3108. end;
  3109. procedure StrToTouchTime(const S: String);
  3110. var
  3111. P: PChar;
  3112. Hour, Minute, Second: Integer;
  3113. begin
  3114. if CompareText(S, 'current') = 0 then begin
  3115. TouchTimeOption := ttCurrent;
  3116. Exit;
  3117. end;
  3118. if CompareText(S, 'none') = 0 then begin
  3119. TouchTimeOption := ttNone;
  3120. Exit;
  3121. end;
  3122. P := PChar(S);
  3123. Hour := ExtractNumber(P);
  3124. if (Hour > 23) or (P^ <> ':') then
  3125. Invalid;
  3126. Inc(P);
  3127. Minute := ExtractNumber(P);
  3128. if Minute > 59 then
  3129. Invalid;
  3130. if P^ = #0 then
  3131. Second := 0
  3132. else begin
  3133. if P^ <> ':' then
  3134. Invalid;
  3135. Inc(P);
  3136. Second := ExtractNumber(P);
  3137. if (Second > 59) or (P^ <> #0) then
  3138. Invalid;
  3139. end;
  3140. TouchTimeOption := ttExplicit;
  3141. TouchTimeHour := Hour;
  3142. TouchTimeMinute := Minute;
  3143. TouchTimeSecond := Second;
  3144. end;
  3145. function StrToArchitectures(S: String; const Only64Bit: Boolean): TSetupProcessorArchitectures;
  3146. const
  3147. ProcessorFlags: array[0..3] of PChar = ('x86', 'x64', 'ia64', 'arm64');
  3148. begin
  3149. Result := [];
  3150. while True do
  3151. case ExtractFlag(S, ProcessorFlags) of
  3152. -2: Break;
  3153. -1: Invalid;
  3154. 0: if Only64Bit then
  3155. Invalid
  3156. else
  3157. Include(Result, paX86);
  3158. 1: Include(Result, paX64);
  3159. 2: Include(Result, paIA64);
  3160. 3: Include(Result, paARM64);
  3161. end;
  3162. end;
  3163. function StrToPrivilegesRequiredOverrides(S: String): TSetupPrivilegesRequiredOverrides;
  3164. const
  3165. Overrides: array[0..1] of PChar = ('commandline', 'dialog');
  3166. begin
  3167. Result := [];
  3168. while True do
  3169. case ExtractFlag(S, Overrides) of
  3170. -2: Break;
  3171. -1: Invalid;
  3172. 0: Include(Result, proCommandLine);
  3173. 1: Result := Result + [proCommandLine, proDialog];
  3174. end;
  3175. end;
  3176. procedure StrToPercentages(const S: String; var X, Y: Integer; const Min, Max: Integer);
  3177. var
  3178. I: Integer;
  3179. begin
  3180. I := Pos(',', S);
  3181. if I = Length(S) then Invalid;
  3182. if I <> 0 then begin
  3183. X := StrToIntDef(Copy(S, 1, I-1), -1);
  3184. Y := StrToIntDef(Copy(S, I+1, Maxint), -1);
  3185. end else begin
  3186. X := StrToIntDef(S, -1);
  3187. Y := X;
  3188. end;
  3189. if (X < Min) or (X > Max) or (Y < Min) or (Y > Max) then
  3190. Invalid;
  3191. end;
  3192. var
  3193. P: Integer;
  3194. AIncludes: TStringList;
  3195. SignTool, SignToolParams: String;
  3196. begin
  3197. SeparateDirective(Line, KeyName, Value);
  3198. if KeyName = '' then
  3199. Exit;
  3200. I := GetEnumValue(TypeInfo(TSetupSectionDirective), 'ss' + KeyName);
  3201. if I = -1 then
  3202. AbortCompileOnLineFmt(SCompilerUnknownDirective, ['Setup', KeyName]);
  3203. Directive := TSetupSectionDirective(I);
  3204. if (Directive <> ssSignTool) and (SetupDirectiveLines[Directive] <> 0) then
  3205. AbortCompileOnLineFmt(SCompilerEntryAlreadySpecified, ['Setup', KeyName]);
  3206. SetupDirectiveLines[Directive] := LineNumber;
  3207. case Directive of
  3208. ssAllowCancelDuringInstall: begin
  3209. SetSetupHeaderOption(shAllowCancelDuringInstall);
  3210. end;
  3211. ssAllowNetworkDrive: begin
  3212. SetSetupHeaderOption(shAllowNetworkDrive);
  3213. end;
  3214. ssAllowNoIcons: begin
  3215. SetSetupHeaderOption(shAllowNoIcons);
  3216. end;
  3217. ssAllowRootDirectory: begin
  3218. SetSetupHeaderOption(shAllowRootDirectory);
  3219. end;
  3220. ssAllowUNCPath: begin
  3221. SetSetupHeaderOption(shAllowUNCPath);
  3222. end;
  3223. ssAlwaysRestart: begin
  3224. SetSetupHeaderOption(shAlwaysRestart);
  3225. end;
  3226. ssAlwaysUsePersonalGroup: begin
  3227. SetSetupHeaderOption(shAlwaysUsePersonalGroup);
  3228. end;
  3229. ssAlwaysShowComponentsList: begin
  3230. SetSetupHeaderOption(shAlwaysShowComponentsList);
  3231. end;
  3232. ssAlwaysShowDirOnReadyPage: begin
  3233. SetSetupHeaderOption(shAlwaysShowDirOnReadyPage);
  3234. end;
  3235. ssAlwaysShowGroupOnReadyPage: begin
  3236. SetSetupHeaderOption(shAlwaysShowGroupOnReadyPage);
  3237. end;
  3238. ssAppCopyright: begin
  3239. SetupHeader.AppCopyright := Value;
  3240. end;
  3241. ssAppComments: begin
  3242. SetupHeader.AppComments := Value;
  3243. end;
  3244. ssAppContact: begin
  3245. SetupHeader.AppContact := Value;
  3246. end;
  3247. ssAppendDefaultDirName: begin
  3248. SetSetupHeaderOption(shAppendDefaultDirName);
  3249. end;
  3250. ssAppendDefaultGroupName: begin
  3251. SetSetupHeaderOption(shAppendDefaultGroupName);
  3252. end;
  3253. ssAppId: begin
  3254. if Value = '' then
  3255. Invalid;
  3256. SetupHeader.AppId := Value;
  3257. end;
  3258. ssAppModifyPath: begin
  3259. SetupHeader.AppModifyPath := Value;
  3260. end;
  3261. ssAppMutex: begin
  3262. SetupHeader.AppMutex := Trim(Value);
  3263. end;
  3264. ssAppName: begin
  3265. if Value = '' then
  3266. Invalid;
  3267. SetupHeader.AppName := Value;
  3268. end;
  3269. ssAppPublisher: begin
  3270. SetupHeader.AppPublisher := Value;
  3271. end;
  3272. ssAppPublisherURL: begin
  3273. SetupHeader.AppPublisherURL := Value;
  3274. end;
  3275. ssAppReadmeFile: begin
  3276. SetupHeader.AppReadmeFile := Value;
  3277. end;
  3278. ssAppSupportPhone: begin
  3279. SetupHeader.AppSupportPhone := Value;
  3280. end;
  3281. ssAppSupportURL: begin
  3282. SetupHeader.AppSupportURL := Value;
  3283. end;
  3284. ssAppUpdatesURL: begin
  3285. SetupHeader.AppUpdatesURL := Value;
  3286. end;
  3287. ssAppVerName: begin
  3288. if Value = '' then
  3289. Invalid;
  3290. SetupHeader.AppVerName := Value;
  3291. end;
  3292. ssAppVersion: begin
  3293. SetupHeader.AppVersion := Value;
  3294. end;
  3295. ssArchitecturesAllowed: begin
  3296. SetupHeader.ArchitecturesAllowed := StrToArchitectures(Value, False);
  3297. end;
  3298. ssArchitecturesInstallIn64BitMode: begin
  3299. SetupHeader.ArchitecturesInstallIn64BitMode := StrToArchitectures(Value, True);
  3300. end;
  3301. ssASLRCompatible: begin
  3302. ASLRCompatible := StrToBool(Value);
  3303. end;
  3304. ssBackColor: begin
  3305. try
  3306. SetupHeader.BackColor := StringToColor(Value);
  3307. except
  3308. Invalid;
  3309. end;
  3310. end;
  3311. ssBackColor2: begin
  3312. try
  3313. SetupHeader.BackColor2 := StringToColor(Value);
  3314. except
  3315. Invalid;
  3316. end;
  3317. end;
  3318. ssBackColorDirection: begin
  3319. if CompareText(Value, 'toptobottom') = 0 then
  3320. Exclude(SetupHeader.Options, shBackColorHorizontal)
  3321. else if CompareText(Value, 'lefttoright') = 0 then
  3322. Include(SetupHeader.Options, shBackColorHorizontal)
  3323. else
  3324. Invalid;
  3325. end;
  3326. ssBackSolid: begin
  3327. BackSolid := StrToBool(Value);
  3328. end;
  3329. ssChangesAssociations: begin
  3330. SetupHeader.ChangesAssociations := Value;
  3331. end;
  3332. ssChangesEnvironment: begin
  3333. SetupHeader.ChangesEnvironment := Value;
  3334. end;
  3335. ssCloseApplications: begin
  3336. if CompareText(Value, 'force') = 0 then begin
  3337. Include(SetupHeader.Options, shCloseApplications);
  3338. Include(SetupHeader.Options, shForceCloseApplications);
  3339. end else begin
  3340. SetSetupHeaderOption(shCloseApplications);
  3341. Exclude(SetupHeader.Options, shForceCloseApplications);
  3342. end;
  3343. end;
  3344. ssCloseApplicationsFilter: begin
  3345. if Value = '' then
  3346. Invalid;
  3347. AIncludes := TStringList.Create;
  3348. try
  3349. ProcessWildcardsParameter(Value, AIncludes,
  3350. Format(SCompilerDirectivePatternTooLong, ['CloseApplicationsFilter']));
  3351. SetupHeader.CloseApplicationsFilter := StringsToCommaString(AIncludes);
  3352. finally
  3353. AIncludes.Free;
  3354. end;
  3355. end;
  3356. ssCompression: begin
  3357. Value := Lowercase(Trim(Value));
  3358. if Value = 'none' then begin
  3359. CompressMethod := cmStored;
  3360. CompressLevel := 0;
  3361. end
  3362. else if Value = 'zip' then begin
  3363. CompressMethod := cmZip;
  3364. CompressLevel := 7;
  3365. end
  3366. else if Value = 'bzip' then begin
  3367. CompressMethod := cmBzip;
  3368. CompressLevel := 9;
  3369. end
  3370. else if Value = 'lzma' then begin
  3371. CompressMethod := cmLZMA;
  3372. CompressLevel := clLZMAMax;
  3373. end
  3374. else if Value = 'lzma2' then begin
  3375. CompressMethod := cmLZMA2;
  3376. CompressLevel := clLZMAMax;
  3377. end
  3378. else if Copy(Value, 1, 4) = 'zip/' then begin
  3379. I := StrToIntDef(Copy(Value, 5, Maxint), -1);
  3380. if (I < 1) or (I > 9) then
  3381. Invalid;
  3382. CompressMethod := cmZip;
  3383. CompressLevel := I;
  3384. end
  3385. else if Copy(Value, 1, 5) = 'bzip/' then begin
  3386. I := StrToIntDef(Copy(Value, 6, Maxint), -1);
  3387. if (I < 1) or (I > 9) then
  3388. Invalid;
  3389. CompressMethod := cmBzip;
  3390. CompressLevel := I;
  3391. end
  3392. else if Copy(Value, 1, 5) = 'lzma/' then begin
  3393. if not LZMAGetLevel(Copy(Value, 6, Maxint), I) then
  3394. Invalid;
  3395. CompressMethod := cmLZMA;
  3396. CompressLevel := I;
  3397. end
  3398. else if Copy(Value, 1, 6) = 'lzma2/' then begin
  3399. if not LZMAGetLevel(Copy(Value, 7, Maxint), I) then
  3400. Invalid;
  3401. CompressMethod := cmLZMA2;
  3402. CompressLevel := I;
  3403. end
  3404. else
  3405. Invalid;
  3406. end;
  3407. ssCompressionThreads: begin
  3408. if CompareText(Value, 'auto') = 0 then
  3409. { do nothing; it's the default }
  3410. else begin
  3411. if StrToIntRange(Value, 1, 64) = 1 then begin
  3412. InternalCompressProps.NumThreads := 1;
  3413. CompressProps.NumThreads := 1;
  3414. end;
  3415. end;
  3416. end;
  3417. ssCreateAppDir: begin
  3418. SetSetupHeaderOption(shCreateAppDir);
  3419. end;
  3420. ssCreateUninstallRegKey: begin
  3421. SetupHeader.CreateUninstallRegKey := Value;
  3422. end;
  3423. ssDefaultDialogFontName: begin
  3424. DefaultDialogFontName := Trim(Value);
  3425. end;
  3426. ssDefaultDirName: begin
  3427. SetupHeader.DefaultDirName := Value;
  3428. end;
  3429. ssDefaultGroupName: begin
  3430. SetupHeader.DefaultGroupName := Value;
  3431. end;
  3432. ssDefaultUserInfoName: begin
  3433. SetupHeader.DefaultUserInfoName := Value;
  3434. end;
  3435. ssDefaultUserInfoOrg: begin
  3436. SetupHeader.DefaultUserInfoOrg := Value;
  3437. end;
  3438. ssDefaultUserInfoSerial: begin
  3439. SetupHeader.DefaultUserInfoSerial := Value;
  3440. end;
  3441. ssDEPCompatible: begin
  3442. DEPCompatible := StrToBool(Value);
  3443. end;
  3444. ssDirExistsWarning: begin
  3445. if CompareText(Value, 'auto') = 0 then
  3446. SetupHeader.DirExistsWarning := ddAuto
  3447. else if StrToBool(Value) then
  3448. { ^ exception will be raised if Value is invalid }
  3449. SetupHeader.DirExistsWarning := ddYes
  3450. else
  3451. SetupHeader.DirExistsWarning := ddNo;
  3452. end;
  3453. ssDisableDirPage: begin
  3454. if CompareText(Value, 'auto') = 0 then
  3455. SetupHeader.DisableDirPage := dpAuto
  3456. else if StrToBool(Value) then
  3457. { ^ exception will be raised if Value is invalid }
  3458. SetupHeader.DisableDirPage := dpYes
  3459. else
  3460. SetupHeader.DisableDirPage := dpNo;
  3461. end;
  3462. ssDisableFinishedPage: begin
  3463. SetSetupHeaderOption(shDisableFinishedPage);
  3464. end;
  3465. ssDisableProgramGroupPage: begin
  3466. if CompareText(Value, 'auto') = 0 then
  3467. SetupHeader.DisableProgramGroupPage := dpAuto
  3468. else if StrToBool(Value) then
  3469. { ^ exception will be raised if Value is invalid }
  3470. SetupHeader.DisableProgramGroupPage := dpYes
  3471. else
  3472. SetupHeader.DisableProgramGroupPage := dpNo;
  3473. end;
  3474. ssDisableReadyMemo: begin
  3475. SetSetupHeaderOption(shDisableReadyMemo);
  3476. end;
  3477. ssDisableReadyPage: begin
  3478. SetSetupHeaderOption(shDisableReadyPage);
  3479. end;
  3480. ssDisableStartupPrompt: begin
  3481. SetSetupHeaderOption(shDisableStartupPrompt);
  3482. end;
  3483. ssDisableWelcomePage: begin
  3484. SetSetupHeaderOption(shDisableWelcomePage);
  3485. end;
  3486. ssDiskClusterSize: begin
  3487. Val(Value, DiskClusterSize, I);
  3488. if I <> 0 then
  3489. Invalid;
  3490. if (DiskClusterSize < 1) or (DiskClusterSize > 32768) then
  3491. AbortCompileOnLine(SCompilerDiskClusterSizeInvalid);
  3492. end;
  3493. ssDiskSliceSize: begin
  3494. if CompareText(Value, 'max') = 0 then
  3495. DiskSliceSize := MaxDiskSliceSize
  3496. else begin
  3497. Val(Value, DiskSliceSize, I);
  3498. if I <> 0 then
  3499. Invalid;
  3500. if (DiskSliceSize < 262144) or (DiskSliceSize > MaxDiskSliceSize) then
  3501. AbortCompileFmt(SCompilerDiskSliceSizeInvalid, [262144, MaxDiskSliceSize]);
  3502. end;
  3503. end;
  3504. ssDiskSpanning: begin
  3505. DiskSpanning := StrToBool(Value);
  3506. end;
  3507. ssDontMergeDuplicateFiles: begin { obsolete; superseded by "MergeDuplicateFiles" }
  3508. if SetupDirectiveLines[ssMergeDuplicateFiles] = 0 then
  3509. DontMergeDuplicateFiles := StrToBool(Value);
  3510. WarningsList.Add(Format(SCompilerEntrySuperseded2, ['Setup', KeyName,
  3511. 'MergeDuplicateFiles']));
  3512. end;
  3513. ssEnableDirDoesntExistWarning: begin
  3514. SetSetupHeaderOption(shEnableDirDoesntExistWarning);
  3515. end;
  3516. ssEncryption:
  3517. begin
  3518. SetSetupHeaderOption(shEncryptionUsed);
  3519. end;
  3520. ssExtraDiskSpaceRequired: begin
  3521. if not StrToInteger64(Value, SetupHeader.ExtraDiskSpaceRequired) then
  3522. Invalid;
  3523. end;
  3524. ssFlatComponentsList: begin
  3525. SetSetupHeaderOption(shFlatComponentsList);
  3526. end;
  3527. ssInfoBeforeFile: begin
  3528. InfoBeforeFile := Value;
  3529. end;
  3530. ssInfoAfterFile: begin
  3531. InfoAfterFile := Value;
  3532. end;
  3533. ssInternalCompressLevel: begin
  3534. Value := Lowercase(Trim(Value));
  3535. if (Value = '0') or (CompareText(Value, 'none') = 0) then
  3536. InternalCompressLevel := 0
  3537. else if not LZMAGetLevel(Value, InternalCompressLevel) then
  3538. Invalid;
  3539. end;
  3540. ssLanguageDetectionMethod: begin
  3541. if CompareText(Value, 'uilanguage') = 0 then
  3542. SetupHeader.LanguageDetectionMethod := ldUILanguage
  3543. else if CompareText(Value, 'locale') = 0 then
  3544. SetupHeader.LanguageDetectionMethod := ldLocale
  3545. else if CompareText(Value, 'none') = 0 then
  3546. SetupHeader.LanguageDetectionMethod := ldNone
  3547. else
  3548. Invalid;
  3549. end;
  3550. ssLicenseFile: begin
  3551. LicenseFile := Value;
  3552. end;
  3553. ssLZMAAlgorithm: begin
  3554. CompressProps.Algorithm := StrToIntRange(Value, 0, 1);
  3555. end;
  3556. ssLZMABlockSize: begin
  3557. CompressProps.BlockSize := StrToIntRange(Value, 1024, 262144) * 1024; //search Lzma2Enc.c for kMaxSize to see this limit: 262144*1024==1<<28
  3558. end;
  3559. ssLZMADictionarySize: begin
  3560. CompressProps.DictionarySize := StrToIntRange(Value, 4, 1048576) * 1024;
  3561. end;
  3562. ssLZMAMatchFinder: begin
  3563. if CompareText(Value, 'BT') = 0 then
  3564. I := 1
  3565. else if CompareText(Value, 'HC') = 0 then
  3566. I := 0
  3567. else
  3568. Invalid;
  3569. CompressProps.BTMode := I;
  3570. end;
  3571. ssLZMANumBlockThreads: begin
  3572. CompressProps.NumBlockThreads := StrToIntRange(Value, 1, 32);
  3573. end;
  3574. ssLZMANumFastBytes: begin
  3575. CompressProps.NumFastBytes := StrToIntRange(Value, 5, 273);
  3576. end;
  3577. ssLZMAUseSeparateProcess: begin
  3578. if CompareText(Value, 'x86') = 0 then
  3579. CompressProps.WorkerProcessFilename := GetLZMAExeFilename(False)
  3580. else if StrToBool(Value) then
  3581. CompressProps.WorkerProcessFilename := GetLZMAExeFilename(True)
  3582. else
  3583. CompressProps.WorkerProcessFilename := '';
  3584. end;
  3585. ssMergeDuplicateFiles: begin
  3586. DontMergeDuplicateFiles := not StrToBool(Value);
  3587. end;
  3588. ssMessagesFile: begin
  3589. AbortCompileOnLine(SCompilerMessagesFileObsolete);
  3590. end;
  3591. ssMinVersion: begin
  3592. if not StrToSetupVersionData(Value, SetupHeader.MinVersion) then
  3593. Invalid;
  3594. if SetupHeader.MinVersion.WinVersion <> 0 then
  3595. AbortCompileOnLine(SCompilerMinVersionWinMustBeZero);
  3596. if SetupHeader.MinVersion.NTVersion < $06010000 then
  3597. AbortCompileOnLineFmt(SCompilerMinVersionNTTooLow, ['6.1']);
  3598. end;
  3599. ssMissingMessagesWarning: begin
  3600. MissingMessagesWarning := StrToBool(Value);
  3601. end;
  3602. ssMissingRunOnceIdsWarning: begin
  3603. MissingRunOnceIdsWarning := StrToBool(Value);
  3604. end;
  3605. ssOnlyBelowVersion: begin
  3606. if not StrToSetupVersionData(Value, SetupHeader.OnlyBelowVersion) then
  3607. Invalid;
  3608. end;
  3609. ssOutput: begin
  3610. if not FixedOutput then
  3611. Output := StrToBool(Value);
  3612. end;
  3613. ssOutputBaseFilename: begin
  3614. if not FixedOutputBaseFilename then
  3615. OutputBaseFilename := Value;
  3616. end;
  3617. ssOutputDir: begin
  3618. if not FixedOutputDir then
  3619. OutputDir := Value;
  3620. end;
  3621. ssOutputManifestFile: begin
  3622. OutputManifestFile := Value;
  3623. end;
  3624. ssPassword: begin
  3625. if Value <> '' then begin
  3626. CryptKey := Value;
  3627. GeneratePasswordHashAndSalt(Value, SetupHeader.PasswordHash,
  3628. SetupHeader.PasswordSalt);
  3629. Include(SetupHeader.Options, shPassword);
  3630. end;
  3631. end;
  3632. ssPrivilegesRequired: begin
  3633. if CompareText(Value, 'none') = 0 then
  3634. SetupHeader.PrivilegesRequired := prNone
  3635. else if CompareText(Value, 'poweruser') = 0 then
  3636. SetupHeader.PrivilegesRequired := prPowerUser
  3637. else if CompareText(Value, 'admin') = 0 then
  3638. SetupHeader.PrivilegesRequired := prAdmin
  3639. else if CompareText(Value, 'lowest') = 0 then
  3640. SetupHeader.PrivilegesRequired := prLowest
  3641. else
  3642. Invalid;
  3643. end;
  3644. ssPrivilegesRequiredOverridesAllowed: begin
  3645. SetupHeader.PrivilegesRequiredOverridesAllowed := StrToPrivilegesRequiredOverrides(Value);
  3646. end;
  3647. ssReserveBytes: begin
  3648. Val(Value, ReserveBytes, I);
  3649. if (I <> 0) or (ReserveBytes < 0) then
  3650. Invalid;
  3651. end;
  3652. ssRestartApplications: begin
  3653. SetSetupHeaderOption(shRestartApplications);
  3654. end;
  3655. ssRestartIfNeededByRun: begin
  3656. SetSetupHeaderOption(shRestartIfNeededByRun);
  3657. end;
  3658. ssSetupIconFile: begin
  3659. SetupIconFilename := Value;
  3660. end;
  3661. ssSetupLogging: begin
  3662. SetSetupHeaderOption(shSetupLogging);
  3663. end;
  3664. ssSetupMutex: begin
  3665. SetupHeader.SetupMutex := Trim(Value);
  3666. end;
  3667. ssShowComponentSizes: begin
  3668. SetSetupHeaderOption(shShowComponentSizes);
  3669. end;
  3670. ssShowLanguageDialog: begin
  3671. if CompareText(Value, 'auto') = 0 then
  3672. SetupHeader.ShowLanguageDialog := slAuto
  3673. else if StrToBool(Value) then
  3674. SetupHeader.ShowLanguageDialog := slYes
  3675. else
  3676. SetupHeader.ShowLanguageDialog := slNo;
  3677. end;
  3678. ssShowTasksTreeLines: begin
  3679. SetSetupHeaderOption(shShowTasksTreeLines);
  3680. end;
  3681. ssShowUndisplayableLanguages: begin
  3682. WarningsList.Add(Format(SCompilerEntryObsolete, ['Setup', KeyName]));
  3683. end;
  3684. ssSignedUninstaller: begin
  3685. SetSetupHeaderOption(shSignedUninstaller);
  3686. end;
  3687. ssSignedUninstallerDir: begin
  3688. if Value = '' then
  3689. Invalid;
  3690. SignedUninstallerDir := Value;
  3691. end;
  3692. ssSignTool: begin
  3693. P := Pos(' ', Value);
  3694. if (P <> 0) then begin
  3695. SignTool := Copy(Value, 1, P-1);
  3696. SignToolParams := Copy(Value, P+1, MaxInt);
  3697. end else begin
  3698. SignTool := Value;
  3699. SignToolParams := '';
  3700. end;
  3701. if FindSignToolIndexByName(SignTool) = -1 then
  3702. Invalid;
  3703. SignTools.Add(SignTool);
  3704. SignToolsParams.Add(SignToolParams);
  3705. end;
  3706. ssSignToolMinimumTimeBetween: begin
  3707. I := StrToIntDef(Value, -1);
  3708. if I < 0 then
  3709. Invalid;
  3710. SignToolMinimumTimeBetween := I;
  3711. end;
  3712. ssSignToolRetryCount: begin
  3713. I := StrToIntDef(Value, -1);
  3714. if I < 0 then
  3715. Invalid;
  3716. SignToolRetryCount := I;
  3717. end;
  3718. ssSignToolRetryDelay: begin
  3719. I := StrToIntDef(Value, -1);
  3720. if I < 0 then
  3721. Invalid;
  3722. SignToolRetryDelay := I;
  3723. end;
  3724. ssSignToolRunMinimized: begin
  3725. SignToolRunMinimized := StrToBool(Value);
  3726. end;
  3727. ssSlicesPerDisk: begin
  3728. I := StrToIntDef(Value, -1);
  3729. if (I < 1) or (I > 26) then
  3730. Invalid;
  3731. SlicesPerDisk := I;
  3732. end;
  3733. ssSolidCompression: begin
  3734. UseSolidCompression := StrToBool(Value);
  3735. end;
  3736. ssSourceDir: begin
  3737. if Value = '' then
  3738. Invalid;
  3739. SourceDir := PrependDirName(Value, OriginalSourceDir);
  3740. end;
  3741. ssTerminalServicesAware: begin
  3742. TerminalServicesAware := StrToBool(Value);
  3743. end;
  3744. ssTimeStampRounding: begin
  3745. I := StrToIntDef(Value, -1);
  3746. { Note: We can't allow really high numbers here because it gets
  3747. multiplied by 10000000 }
  3748. if (I < 0) or (I > 60) then
  3749. Invalid;
  3750. TimeStampRounding := I;
  3751. end;
  3752. ssTimeStampsInUTC: begin
  3753. TimeStampsInUTC := StrToBool(Value);
  3754. end;
  3755. ssTouchDate: begin
  3756. StrToTouchDate(Value);
  3757. end;
  3758. ssTouchTime: begin
  3759. StrToTouchTime(Value);
  3760. end;
  3761. ssUpdateUninstallLogAppName: begin
  3762. SetSetupHeaderOption(shUpdateUninstallLogAppName);
  3763. end;
  3764. ssUninstallable: begin
  3765. SetupHeader.Uninstallable := Value;
  3766. end;
  3767. ssUninstallDisplayIcon: begin
  3768. SetupHeader.UninstallDisplayIcon := Value;
  3769. end;
  3770. ssUninstallDisplayName: begin
  3771. SetupHeader.UninstallDisplayName := Value;
  3772. end;
  3773. ssUninstallDisplaySize: begin
  3774. if not StrToInteger64(Value, SetupHeader.UninstallDisplaySize) or
  3775. ((SetupHeader.UninstallDisplaySize.Lo = 0) and (SetupHeader.UninstallDisplaySize.Hi = 0)) then
  3776. Invalid;
  3777. end;
  3778. ssUninstallFilesDir: begin
  3779. if Value = '' then
  3780. Invalid;
  3781. SetupHeader.UninstallFilesDir := Value;
  3782. end;
  3783. ssUninstallIconFile: begin
  3784. WarningsList.Add(Format(SCompilerEntryObsolete, ['Setup', KeyName]));
  3785. end;
  3786. ssUninstallLogging: begin
  3787. SetSetupHeaderOption(shUninstallLogging);
  3788. end;
  3789. ssUninstallLogMode: begin
  3790. if CompareText(Value, 'append') = 0 then
  3791. SetupHeader.UninstallLogMode := lmAppend
  3792. else if CompareText(Value, 'new') = 0 then
  3793. SetupHeader.UninstallLogMode := lmNew
  3794. else if CompareText(Value, 'overwrite') = 0 then
  3795. SetupHeader.UninstallLogMode := lmOverwrite
  3796. else
  3797. Invalid;
  3798. end;
  3799. ssUninstallRestartComputer: begin
  3800. SetSetupHeaderOption(shUninstallRestartComputer);
  3801. end;
  3802. ssUninstallStyle: begin
  3803. WarningsList.Add(Format(SCompilerEntryObsolete, ['Setup', KeyName]));
  3804. end;
  3805. ssUsePreviousAppDir: begin
  3806. SetSetupHeaderOption(shUsePreviousAppDir);
  3807. end;
  3808. ssNotRecognizedMessagesWarning: begin
  3809. NotRecognizedMessagesWarning := StrToBool(Value);
  3810. end;
  3811. ssUsedUserAreasWarning: begin
  3812. UsedUserAreasWarning := StrToBool(Value);
  3813. end;
  3814. ssUsePreviousGroup: begin
  3815. SetSetupHeaderOption(shUsePreviousGroup);
  3816. end;
  3817. ssUsePreviousLanguage: begin
  3818. SetSetupHeaderOption(shUsePreviousLanguage);
  3819. end;
  3820. ssUsePreviousPrivileges: begin
  3821. SetSetupHeaderOption(shUsePreviousPrivileges);
  3822. end;
  3823. ssUsePreviousSetupType: begin
  3824. SetSetupHeaderOption(shUsePreviousSetupType);
  3825. end;
  3826. ssUsePreviousTasks: begin
  3827. SetSetupHeaderOption(shUsePreviousTasks);
  3828. end;
  3829. ssUsePreviousUserInfo: begin
  3830. SetSetupHeaderOption(shUsePreviousUserInfo);
  3831. end;
  3832. ssUseSetupLdr: begin
  3833. UseSetupLdr := StrToBool(Value);
  3834. end;
  3835. ssUserInfoPage: begin
  3836. SetSetupHeaderOption(shUserInfoPage);
  3837. end;
  3838. ssVersionInfoCompany: begin
  3839. VersionInfoCompany := Value;
  3840. end;
  3841. ssVersionInfoCopyright: begin
  3842. VersionInfoCopyright := Value;
  3843. end;
  3844. ssVersionInfoDescription: begin
  3845. VersionInfoDescription := Value;
  3846. end;
  3847. ssVersionInfoOriginalFileName: begin
  3848. VersionInfoOriginalFileName := Value;
  3849. end;
  3850. ssVersionInfoProductName: begin
  3851. VersionInfoProductName := Value;
  3852. end;
  3853. ssVersionInfoProductVersion: begin
  3854. VersionInfoProductVersionOriginalValue := Value;
  3855. if not StrToVersionNumbers(Value, VersionInfoProductVersion) then
  3856. Invalid;
  3857. end;
  3858. ssVersionInfoProductTextVersion: begin
  3859. VersionInfoProductTextVersion := Value;
  3860. end;
  3861. ssVersionInfoTextVersion: begin
  3862. VersionInfoTextVersion := Value;
  3863. end;
  3864. ssVersionInfoVersion: begin
  3865. VersionInfoVersionOriginalValue := Value;
  3866. if not StrToVersionNumbers(Value, VersionInfoVersion) then
  3867. Invalid;
  3868. end;
  3869. ssWindowResizable: begin
  3870. SetSetupHeaderOption(shWindowResizable);
  3871. end;
  3872. ssWindowShowCaption: begin
  3873. SetSetupHeaderOption(shWindowShowCaption);
  3874. end;
  3875. ssWindowStartMaximized: begin
  3876. SetSetupHeaderOption(shWindowStartMaximized);
  3877. end;
  3878. ssWindowVisible: begin
  3879. SetSetupHeaderOption(shWindowVisible);
  3880. end;
  3881. ssWizardImageAlphaFormat: begin
  3882. if CompareText(Value, 'none') = 0 then
  3883. SetupHeader.WizardImageAlphaFormat := afIgnored
  3884. else if CompareText(Value, 'defined') = 0 then
  3885. SetupHeader.WizardImageAlphaFormat := afDefined
  3886. else if CompareText(Value, 'premultiplied') = 0 then
  3887. SetupHeader.WizardImageAlphaFormat := afPremultiplied
  3888. else
  3889. Invalid;
  3890. end;
  3891. ssWizardImageBackColor, ssWizardSmallImageBackColor: begin
  3892. WarningsList.Add(Format(SCompilerEntryObsolete, ['Setup', KeyName]));
  3893. end;
  3894. ssWizardImageStretch: begin
  3895. SetSetupHeaderOption(shWizardImageStretch);
  3896. end;
  3897. ssWizardImageFile: begin
  3898. WizardImageFile := Value;
  3899. end;
  3900. ssWizardResizable: begin
  3901. SetSetupHeaderOption(shWizardResizable);
  3902. end;
  3903. ssWizardSmallImageFile: begin
  3904. WizardSmallImageFile := Value;
  3905. end;
  3906. ssWizardSizePercent: begin
  3907. StrToPercentages(Value, SetupHeader.WizardSizePercentX,
  3908. SetupHeader.WizardSizePercentY, 100, 150)
  3909. end;
  3910. ssWizardStyle: begin
  3911. if CompareText(Value, 'classic') = 0 then
  3912. SetupHeader.WizardStyle := wsClassic
  3913. else if CompareText(Value, 'modern') = 0 then
  3914. SetupHeader.WizardStyle := wsModern
  3915. else
  3916. Invalid;
  3917. end;
  3918. end;
  3919. end;
  3920. function TSetupCompiler.FindLangEntryIndexByName(const AName: String;
  3921. const Pre: Boolean): Integer;
  3922. var
  3923. I: Integer;
  3924. begin
  3925. if Pre then begin
  3926. for I := 0 to PreLangDataList.Count-1 do begin
  3927. if TPreLangData(PreLangDataList[I]).Name = AName then begin
  3928. Result := I;
  3929. Exit;
  3930. end;
  3931. end;
  3932. AbortCompileOnLineFmt(SCompilerUnknownLanguage, [AName]);
  3933. end;
  3934. for I := 0 to LanguageEntries.Count-1 do begin
  3935. if PSetupLanguageEntry(LanguageEntries[I]).Name = AName then begin
  3936. Result := I;
  3937. Exit;
  3938. end;
  3939. end;
  3940. Result := -1;
  3941. AbortCompileOnLineFmt(SCompilerUnknownLanguage, [AName]);
  3942. end;
  3943. function TSetupCompiler.FindSignToolIndexByName(const AName: String): Integer;
  3944. var
  3945. I: Integer;
  3946. begin
  3947. for I := 0 to SignToolList.Count-1 do begin
  3948. if TSignTool(SignToolList[I]).Name = AName then begin
  3949. Result := I;
  3950. Exit;
  3951. end;
  3952. end;
  3953. Result := -1;
  3954. end;
  3955. procedure TSetupCompiler.EnumLangOptionsPreProc(const Line: PChar; const Ext: Integer);
  3956. procedure ApplyToLangEntryPre(const KeyName, Value: String;
  3957. const PreLangData: TPreLangData; const AffectsMultipleLangs: Boolean);
  3958. var
  3959. I: Integer;
  3960. Directive: TLangOptionsSectionDirective;
  3961. procedure Invalid;
  3962. begin
  3963. AbortCompileOnLineFmt(SCompilerEntryInvalid2, ['LangOptions', KeyName]);
  3964. end;
  3965. function StrToIntCheck(const S: String): Integer;
  3966. var
  3967. E: Integer;
  3968. begin
  3969. Val(S, Result, E);
  3970. if E <> 0 then
  3971. Invalid;
  3972. end;
  3973. begin
  3974. I := GetEnumValue(TypeInfo(TLangOptionsSectionDirective), 'ls' + KeyName);
  3975. if I = -1 then
  3976. AbortCompileOnLineFmt(SCompilerUnknownDirective, ['LangOptions', KeyName]);
  3977. Directive := TLangOptionsSectionDirective(I);
  3978. case Directive of
  3979. lsLanguageCodePage: begin
  3980. if AffectsMultipleLangs then
  3981. AbortCompileOnLineFmt(SCompilerCantSpecifyLangOption, [KeyName]);
  3982. PreLangData.LanguageCodePage := StrToIntCheck(Value);
  3983. if (PreLangData.LanguageCodePage <> 0) and
  3984. not IsValidCodePage(PreLangData.LanguageCodePage) then
  3985. Invalid;
  3986. end;
  3987. end;
  3988. end;
  3989. var
  3990. KeyName, Value: String;
  3991. I, LangIndex: Integer;
  3992. begin
  3993. SeparateDirective(Line, KeyName, Value);
  3994. LangIndex := ExtractLangIndex(Self, KeyName, Ext, True);
  3995. if LangIndex = -1 then begin
  3996. for I := 0 to PreLangDataList.Count-1 do
  3997. ApplyToLangEntryPre(KeyName, Value, TPreLangData(PreLangDataList[I]),
  3998. PreLangDataList.Count > 1);
  3999. end else
  4000. ApplyToLangEntryPre(KeyName, Value, TPreLangData(PreLangDataList[LangIndex]), False);
  4001. end;
  4002. procedure TSetupCompiler.EnumLangOptionsProc(const Line: PChar; const Ext: Integer);
  4003. procedure ApplyToLangEntry(const KeyName, Value: String;
  4004. var LangOptions: TSetupLanguageEntry; const AffectsMultipleLangs: Boolean);
  4005. var
  4006. I: Integer;
  4007. Directive: TLangOptionsSectionDirective;
  4008. procedure Invalid;
  4009. begin
  4010. AbortCompileOnLineFmt(SCompilerEntryInvalid2, ['LangOptions', KeyName]);
  4011. end;
  4012. function StrToIntCheck(const S: String): Integer;
  4013. var
  4014. E: Integer;
  4015. begin
  4016. Val(S, Result, E);
  4017. if E <> 0 then
  4018. Invalid;
  4019. end;
  4020. function ConvertLanguageName(N: String): String;
  4021. var
  4022. I, J, L: Integer;
  4023. W: Word;
  4024. begin
  4025. N := Trim(N);
  4026. if N = '' then
  4027. Invalid;
  4028. Result := '';
  4029. I := 1;
  4030. while I <= Length(N) do begin
  4031. if N[I] = '<' then begin
  4032. { Handle embedded Unicode characters ('<nnnn>') }
  4033. if (I+5 > Length(N)) or (N[I+5] <> '>') then
  4034. Invalid;
  4035. for J := I+1 to I+4 do
  4036. if not CharInSet(UpCase(N[J]), ['0'..'9', 'A'..'F']) then
  4037. Invalid;
  4038. W := StrToIntCheck('$' + Copy(N, I+1, 4));
  4039. Inc(I, 6);
  4040. end
  4041. else begin
  4042. W := Ord(N[I]);
  4043. Inc(I);
  4044. end;
  4045. L := Length(Result);
  4046. SetLength(Result, L + (SizeOf(Word) div SizeOf(Char)));
  4047. Word((@Result[L+1])^) := W;
  4048. end;
  4049. end;
  4050. begin
  4051. I := GetEnumValue(TypeInfo(TLangOptionsSectionDirective), 'ls' + KeyName);
  4052. if I = -1 then
  4053. AbortCompileOnLineFmt(SCompilerUnknownDirective, ['LangOptions', KeyName]);
  4054. Directive := TLangOptionsSectionDirective(I);
  4055. case Directive of
  4056. lsCopyrightFontName: begin
  4057. LangOptions.CopyrightFontName := Trim(Value);
  4058. end;
  4059. lsCopyrightFontSize: begin
  4060. LangOptions.CopyrightFontSize := StrToIntCheck(Value);
  4061. end;
  4062. lsDialogFontName: begin
  4063. LangOptions.DialogFontName := Trim(Value);
  4064. end;
  4065. lsDialogFontSize: begin
  4066. LangOptions.DialogFontSize := StrToIntCheck(Value);
  4067. end;
  4068. lsDialogFontStandardHeight: begin
  4069. WarningsList.Add(Format(SCompilerEntryObsolete, ['LangOptions', KeyName]));
  4070. end;
  4071. lsLanguageCodePage: begin
  4072. if AffectsMultipleLangs then
  4073. AbortCompileOnLineFmt(SCompilerCantSpecifyLangOption, [KeyName]);
  4074. StrToIntCheck(Value);
  4075. end;
  4076. lsLanguageID: begin
  4077. if AffectsMultipleLangs then
  4078. AbortCompileOnLineFmt(SCompilerCantSpecifyLangOption, [KeyName]);
  4079. LangOptions.LanguageID := StrToIntCheck(Value);
  4080. end;
  4081. lsLanguageName: begin
  4082. if AffectsMultipleLangs then
  4083. AbortCompileOnLineFmt(SCompilerCantSpecifyLangOption, [KeyName]);
  4084. LangOptions.LanguageName := ConvertLanguageName(Value);
  4085. end;
  4086. lsRightToLeft: begin
  4087. if not TryStrToBoolean(Value, LangOptions.RightToLeft) then
  4088. Invalid;
  4089. end;
  4090. lsTitleFontName: begin
  4091. LangOptions.TitleFontName := Trim(Value);
  4092. end;
  4093. lsTitleFontSize: begin
  4094. LangOptions.TitleFontSize := StrToIntCheck(Value);
  4095. end;
  4096. lsWelcomeFontName: begin
  4097. LangOptions.WelcomeFontName := Trim(Value);
  4098. end;
  4099. lsWelcomeFontSize: begin
  4100. LangOptions.WelcomeFontSize := StrToIntCheck(Value);
  4101. end;
  4102. end;
  4103. end;
  4104. var
  4105. KeyName, Value: String;
  4106. I, LangIndex: Integer;
  4107. begin
  4108. SeparateDirective(Line, KeyName, Value);
  4109. LangIndex := ExtractLangIndex(Self, KeyName, Ext, False);
  4110. if LangIndex = -1 then begin
  4111. for I := 0 to LanguageEntries.Count-1 do
  4112. ApplyToLangEntry(KeyName, Value, PSetupLanguageEntry(LanguageEntries[I])^,
  4113. LanguageEntries.Count > 1);
  4114. end else
  4115. ApplyToLangEntry(KeyName, Value, PSetupLanguageEntry(LanguageEntries[LangIndex])^, False);
  4116. end;
  4117. procedure TSetupCompiler.EnumTypesProc(const Line: PChar; const Ext: Integer);
  4118. function IsCustomTypeAlreadyDefined: Boolean;
  4119. var
  4120. I: Integer;
  4121. begin
  4122. for I := 0 to TypeEntries.Count-1 do
  4123. if toIsCustom in PSetupTypeEntry(TypeEntries[I]).Options then begin
  4124. Result := True;
  4125. Exit;
  4126. end;
  4127. Result := False;
  4128. end;
  4129. type
  4130. TParam = (paFlags, paName, paDescription, paLanguages, paCheck, paMinVersion,
  4131. paOnlyBelowVersion);
  4132. const
  4133. ParamTypesName = 'Name';
  4134. ParamTypesDescription = 'Description';
  4135. ParamInfo: array[TParam] of TParamInfo = (
  4136. (Name: ParamCommonFlags; Flags: []),
  4137. (Name: ParamTypesName; Flags: [piRequired, piNoEmpty]),
  4138. (Name: ParamTypesDescription; Flags: [piRequired, piNoEmpty]),
  4139. (Name: ParamCommonLanguages; Flags: []),
  4140. (Name: ParamCommonCheck; Flags: []),
  4141. (Name: ParamCommonMinVersion; Flags: []),
  4142. (Name: ParamCommonOnlyBelowVersion; Flags: []));
  4143. Flags: array[0..0] of PChar = (
  4144. 'iscustom');
  4145. var
  4146. Values: array[TParam] of TParamValue;
  4147. NewTypeEntry: PSetupTypeEntry;
  4148. begin
  4149. ExtractParameters(Line, ParamInfo, Values);
  4150. NewTypeEntry := AllocMem(SizeOf(TSetupTypeEntry));
  4151. try
  4152. with NewTypeEntry^ do begin
  4153. MinVersion := SetupHeader.MinVersion;
  4154. Typ := ttUser;
  4155. { Flags }
  4156. while True do
  4157. case ExtractFlag(Values[paFlags].Data, Flags) of
  4158. -2: Break;
  4159. -1: AbortCompileParamError(SCompilerParamUnknownFlag2, ParamCommonFlags);
  4160. 0: Include(Options, toIsCustom);
  4161. end;
  4162. { Name }
  4163. Name := LowerCase(Values[paName].Data);
  4164. { Description }
  4165. Description := Values[paDescription].Data;
  4166. { Common parameters }
  4167. ProcessExpressionParameter(ParamCommonLanguages, Values[paLanguages].Data, EvalLanguageIdentifier, False, Languages);
  4168. Check := Values[paCheck].Data;
  4169. ProcessMinVersionParameter(Values[paMinVersion], MinVersion);
  4170. ProcessOnlyBelowVersionParameter(Values[paOnlyBelowVersion], OnlyBelowVersion);
  4171. if (toIsCustom in Options) and IsCustomTypeAlreadyDefined then
  4172. AbortCompileOnLine(SCompilerTypesCustomTypeAlreadyDefined);
  4173. CheckConst(Description, MinVersion, []);
  4174. CheckCheckOrInstall(ParamCommonCheck, Check, cikCheck);
  4175. end;
  4176. except
  4177. SEFreeRec(NewTypeEntry, SetupTypeEntryStrings, SetupTypeEntryAnsiStrings);
  4178. raise;
  4179. end;
  4180. TypeEntries.Add(NewTypeEntry);
  4181. end;
  4182. procedure TSetupCompiler.EnumComponentsProc(const Line: PChar; const Ext: Integer);
  4183. type
  4184. TParam = (paFlags, paName, paDescription, paExtraDiskSpaceRequired, paTypes,
  4185. paLanguages, paCheck, paMinVersion, paOnlyBelowVersion);
  4186. const
  4187. ParamComponentsName = 'Name';
  4188. ParamComponentsDescription = 'Description';
  4189. ParamComponentsExtraDiskSpaceRequired = 'ExtraDiskSpaceRequired';
  4190. ParamComponentsTypes = 'Types';
  4191. ParamInfo: array[TParam] of TParamInfo = (
  4192. (Name: ParamCommonFlags; Flags: []),
  4193. (Name: ParamComponentsName; Flags: [piRequired, piNoEmpty]),
  4194. (Name: ParamComponentsDescription; Flags: [piRequired, piNoEmpty]),
  4195. (Name: ParamComponentsExtraDiskSpaceRequired; Flags: []),
  4196. (Name: ParamComponentsTypes; Flags: []),
  4197. (Name: ParamCommonLanguages; Flags: []),
  4198. (Name: ParamCommonCheck; Flags: []),
  4199. (Name: ParamCommonMinVersion; Flags: []),
  4200. (Name: ParamCommonOnlyBelowVersion; Flags: []));
  4201. Flags: array[0..5] of PChar = (
  4202. 'fixed', 'restart', 'disablenouninstallwarning', 'exclusive',
  4203. 'dontinheritcheck', 'checkablealone');
  4204. var
  4205. Values: array[TParam] of TParamValue;
  4206. NewComponentEntry: PSetupComponentEntry;
  4207. PrevLevel, I: Integer;
  4208. begin
  4209. ExtractParameters(Line, ParamInfo, Values);
  4210. NewComponentEntry := AllocMem(SizeOf(TSetupComponentEntry));
  4211. try
  4212. with NewComponentEntry^ do begin
  4213. MinVersion := SetupHeader.MinVersion;
  4214. { Flags }
  4215. while True do
  4216. case ExtractFlag(Values[paFlags].Data, Flags) of
  4217. -2: Break;
  4218. -1: AbortCompileParamError(SCompilerParamUnknownFlag2, ParamCommonFlags);
  4219. 0: Include(Options, coFixed);
  4220. 1: Include(Options, coRestart);
  4221. 2: Include(Options, coDisableNoUninstallWarning);
  4222. 3: Include(Options, coExclusive);
  4223. 4: Include(Options, coDontInheritCheck);
  4224. 5: Used := True;
  4225. end;
  4226. { Name }
  4227. Name := LowerCase(Values[paName].Data);
  4228. StringChange(Name, '/', '\');
  4229. if not IsValidIdentString(Name, True, False) then
  4230. AbortCompileOnLine(SCompilerComponentsOrTasksBadName);
  4231. Level := CountChars(Name, '\');
  4232. if ComponentEntries.Count > 0 then
  4233. PrevLevel := PSetupComponentEntry(ComponentEntries[ComponentEntries.Count-1]).Level
  4234. else
  4235. PrevLevel := -1;
  4236. if Level > PrevLevel + 1 then
  4237. AbortCompileOnLine(SCompilerComponentsInvalidLevel);
  4238. { Description }
  4239. Description := Values[paDescription].Data;
  4240. { ExtraDiskSpaceRequired }
  4241. if Values[paExtraDiskSpaceRequired].Found then begin
  4242. if not StrToInteger64(Values[paExtraDiskSpaceRequired].Data, ExtraDiskSpaceRequired) then
  4243. AbortCompileParamError(SCompilerParamInvalid2, ParamComponentsExtraDiskSpaceRequired);
  4244. end;
  4245. { Types }
  4246. while True do begin
  4247. I := ExtractType(Values[paTypes].Data, TypeEntries);
  4248. case I of
  4249. -2: Break;
  4250. -1: AbortCompileParamError(SCompilerParamUnknownType, ParamComponentsTypes);
  4251. else begin
  4252. if TypeEntries.Count <> 0 then
  4253. AddToCommaText(Types, PSetupTypeEntry(TypeEntries[I]).Name)
  4254. else
  4255. AddToCommaText(Types, DefaultTypeEntryNames[I]);
  4256. end;
  4257. end;
  4258. end;
  4259. { Common parameters }
  4260. ProcessExpressionParameter(ParamCommonLanguages, Values[paLanguages].Data, EvalLanguageIdentifier, False, Languages);
  4261. Check := Values[paCheck].Data;
  4262. ProcessMinVersionParameter(Values[paMinVersion], MinVersion);
  4263. ProcessOnlyBelowVersionParameter(Values[paOnlyBelowVersion], OnlyBelowVersion);
  4264. if (coDontInheritCheck in Options) and (coExclusive in Options) then
  4265. AbortCompileOnLineFmt(SCompilerParamErrorBadCombo2,
  4266. [ParamCommonFlags, 'dontinheritcheck', 'exclusive']);
  4267. CheckConst(Description, MinVersion, []);
  4268. CheckCheckOrInstall(ParamCommonCheck, Check, cikCheck);
  4269. end;
  4270. except
  4271. SEFreeRec(NewComponentEntry, SetupComponentEntryStrings, SetupComponentEntryAnsiStrings);
  4272. raise;
  4273. end;
  4274. ComponentEntries.Add(NewComponentEntry);
  4275. end;
  4276. procedure TSetupCompiler.EnumTasksProc(const Line: PChar; const Ext: Integer);
  4277. type
  4278. TParam = (paFlags, paName, paDescription, paGroupDescription, paComponents,
  4279. paLanguages, paCheck, paMinVersion, paOnlyBelowVersion);
  4280. const
  4281. ParamTasksName = 'Name';
  4282. ParamTasksDescription = 'Description';
  4283. ParamTasksGroupDescription = 'GroupDescription';
  4284. ParamInfo: array[TParam] of TParamInfo = (
  4285. (Name: ParamCommonFlags; Flags: []),
  4286. (Name: ParamTasksName; Flags: [piRequired, piNoEmpty, piNoQuotes]),
  4287. (Name: ParamTasksDescription; Flags: [piRequired, piNoEmpty]),
  4288. (Name: ParamTasksGroupDescription; Flags: [piNoEmpty]),
  4289. (Name: ParamCommonComponents; Flags: []),
  4290. (Name: ParamCommonLanguages; Flags: []),
  4291. (Name: ParamCommonCheck; Flags: []),
  4292. (Name: ParamCommonMinVersion; Flags: []),
  4293. (Name: ParamCommonOnlyBelowVersion; Flags: []));
  4294. Flags: array[0..5] of PChar = (
  4295. 'exclusive', 'unchecked', 'restart', 'checkedonce', 'dontinheritcheck',
  4296. 'checkablealone');
  4297. var
  4298. Values: array[TParam] of TParamValue;
  4299. NewTaskEntry: PSetupTaskEntry;
  4300. PrevLevel: Integer;
  4301. begin
  4302. ExtractParameters(Line, ParamInfo, Values);
  4303. NewTaskEntry := AllocMem(SizeOf(TSetupTaskEntry));
  4304. try
  4305. with NewTaskEntry^ do begin
  4306. MinVersion := SetupHeader.MinVersion;
  4307. { Flags }
  4308. while True do
  4309. case ExtractFlag(Values[paFlags].Data, Flags) of
  4310. -2: Break;
  4311. -1: AbortCompileParamError(SCompilerParamUnknownFlag2, ParamCommonFlags);
  4312. 0: Include(Options, toExclusive);
  4313. 1: Include(Options, toUnchecked);
  4314. 2: Include(Options, toRestart);
  4315. 3: Include(Options, toCheckedOnce);
  4316. 4: Include(Options, toDontInheritCheck);
  4317. 5: Used := True;
  4318. end;
  4319. { Name }
  4320. Name := LowerCase(Values[paName].Data);
  4321. StringChange(Name, '/', '\');
  4322. if not IsValidIdentString(Name, True, False) then
  4323. AbortCompileOnLine(SCompilerComponentsOrTasksBadName);
  4324. Level := CountChars(Name, '\');
  4325. if TaskEntries.Count > 0 then
  4326. PrevLevel := PSetupTaskEntry(TaskEntries[TaskEntries.Count-1]).Level
  4327. else
  4328. PrevLevel := -1;
  4329. if Level > PrevLevel + 1 then
  4330. AbortCompileOnLine(SCompilerTasksInvalidLevel);
  4331. { Description }
  4332. Description := Values[paDescription].Data;
  4333. { GroupDescription }
  4334. GroupDescription := Values[paGroupDescription].Data;
  4335. { Common parameters }
  4336. ProcessExpressionParameter(ParamCommonComponents, Values[paComponents].Data, EvalComponentIdentifier, True, Components);
  4337. ProcessExpressionParameter(ParamCommonLanguages, Values[paLanguages].Data, EvalLanguageIdentifier, False, Languages);
  4338. Check := Values[paCheck].Data;
  4339. ProcessMinVersionParameter(Values[paMinVersion], MinVersion);
  4340. ProcessOnlyBelowVersionParameter(Values[paOnlyBelowVersion], OnlyBelowVersion);
  4341. if (toDontInheritCheck in Options) and (toExclusive in Options) then
  4342. AbortCompileOnLineFmt(SCompilerParamErrorBadCombo2,
  4343. [ParamCommonFlags, 'dontinheritcheck', 'exclusive']);
  4344. CheckConst(Description, MinVersion, []);
  4345. CheckConst(GroupDescription, MinVersion, []);
  4346. CheckCheckOrInstall(ParamCommonCheck, Check, cikCheck);
  4347. end;
  4348. except
  4349. SEFreeRec(NewTaskEntry, SetupTaskEntryStrings, SetupTaskEntryAnsiStrings);
  4350. raise;
  4351. end;
  4352. TaskEntries.Add(NewTaskEntry);
  4353. end;
  4354. const
  4355. FILE_ATTRIBUTE_NOT_CONTENT_INDEXED = $00002000;
  4356. procedure TSetupCompiler.EnumDirsProc(const Line: PChar; const Ext: Integer);
  4357. type
  4358. TParam = (paFlags, paName, paAttribs, paPermissions, paComponents, paTasks,
  4359. paLanguages, paCheck, paBeforeInstall, paAfterInstall, paMinVersion,
  4360. paOnlyBelowVersion);
  4361. const
  4362. ParamDirsName = 'Name';
  4363. ParamDirsAttribs = 'Attribs';
  4364. ParamDirsPermissions = 'Permissions';
  4365. ParamInfo: array[TParam] of TParamInfo = (
  4366. (Name: ParamCommonFlags; Flags: []),
  4367. (Name: ParamDirsName; Flags: [piRequired, piNoEmpty, piNoQuotes]),
  4368. (Name: ParamDirsAttribs; Flags: []),
  4369. (Name: ParamDirsPermissions; Flags: []),
  4370. (Name: ParamCommonComponents; Flags: []),
  4371. (Name: ParamCommonTasks; Flags: []),
  4372. (Name: ParamCommonLanguages; Flags: []),
  4373. (Name: ParamCommonCheck; Flags: []),
  4374. (Name: ParamCommonBeforeInstall; Flags: []),
  4375. (Name: ParamCommonAfterInstall; Flags: []),
  4376. (Name: ParamCommonMinVersion; Flags: []),
  4377. (Name: ParamCommonOnlyBelowVersion; Flags: []));
  4378. Flags: array[0..4] of PChar = (
  4379. 'uninsneveruninstall', 'deleteafterinstall', 'uninsalwaysuninstall',
  4380. 'setntfscompression', 'unsetntfscompression');
  4381. AttribsFlags: array[0..3] of PChar = (
  4382. 'readonly', 'hidden', 'system', 'notcontentindexed');
  4383. AccessMasks: array[0..2] of TNameAndAccessMask = (
  4384. (Name: 'full'; Mask: $1F01FF),
  4385. (Name: 'modify'; Mask: $1301BF),
  4386. (Name: 'readexec'; Mask: $1200A9));
  4387. var
  4388. Values: array[TParam] of TParamValue;
  4389. NewDirEntry: PSetupDirEntry;
  4390. begin
  4391. ExtractParameters(Line, ParamInfo, Values);
  4392. NewDirEntry := AllocMem(SizeOf(TSetupDirEntry));
  4393. try
  4394. with NewDirEntry^ do begin
  4395. MinVersion := SetupHeader.MinVersion;
  4396. { Flags }
  4397. while True do
  4398. case ExtractFlag(Values[paFlags].Data, Flags) of
  4399. -2: Break;
  4400. -1: AbortCompileParamError(SCompilerParamUnknownFlag2, ParamCommonFlags);
  4401. 0: Include(Options, doUninsNeverUninstall);
  4402. 1: Include(Options, doDeleteAfterInstall);
  4403. 2: Include(Options, doUninsAlwaysUninstall);
  4404. 3: Include(Options, doSetNTFSCompression);
  4405. 4: Include(Options, doUnsetNTFSCompression);
  4406. end;
  4407. { Name }
  4408. DirName := Values[paName].Data;
  4409. { Attribs }
  4410. while True do
  4411. case ExtractFlag(Values[paAttribs].Data, AttribsFlags) of
  4412. -2: Break;
  4413. -1: AbortCompileParamError(SCompilerParamUnknownFlag2, ParamDirsAttribs);
  4414. 0: Attribs := Attribs or FILE_ATTRIBUTE_READONLY;
  4415. 1: Attribs := Attribs or FILE_ATTRIBUTE_HIDDEN;
  4416. 2: Attribs := Attribs or FILE_ATTRIBUTE_SYSTEM;
  4417. 3: Attribs := Attribs or FILE_ATTRIBUTE_NOT_CONTENT_INDEXED;
  4418. end;
  4419. { Permissions }
  4420. ProcessPermissionsParameter(Values[paPermissions].Data, AccessMasks,
  4421. PermissionsEntry);
  4422. { Common parameters }
  4423. ProcessExpressionParameter(ParamCommonComponents, Values[paComponents].Data, EvalComponentIdentifier, True, Components);
  4424. ProcessExpressionParameter(ParamCommonTasks, Values[paTasks].Data, EvalTaskIdentifier, True, Tasks);
  4425. ProcessExpressionParameter(ParamCommonLanguages, Values[paLanguages].Data, EvalLanguageIdentifier, False, Languages);
  4426. Check := Values[paCheck].Data;
  4427. BeforeInstall := Values[paBeforeInstall].Data;
  4428. AfterInstall := Values[paAfterInstall].Data;
  4429. ProcessMinVersionParameter(Values[paMinVersion], MinVersion);
  4430. ProcessOnlyBelowVersionParameter(Values[paOnlyBelowVersion], OnlyBelowVersion);
  4431. if (doUninsNeverUninstall in Options) and
  4432. (doUninsAlwaysUninstall in Options) then
  4433. AbortCompileOnLineFmt(SCompilerParamErrorBadCombo2,
  4434. [ParamCommonFlags, 'uninsneveruninstall', 'uninsalwaysuninstall']);
  4435. if (doSetNTFSCompression in Options) and
  4436. (doUnsetNTFSCompression in Options) then
  4437. AbortCompileOnLineFmt(SCompilerParamErrorBadCombo2,
  4438. [ParamCommonFlags, 'setntfscompression', 'unsetntfscompression']);
  4439. CheckCheckOrInstall(ParamCommonCheck, Check, cikCheck);
  4440. CheckCheckOrInstall(ParamCommonBeforeInstall, BeforeInstall, cikInstall);
  4441. CheckCheckOrInstall(ParamCommonAfterInstall, AfterInstall, cikInstall);
  4442. CheckConst(DirName, MinVersion, []);
  4443. end;
  4444. except
  4445. SEFreeRec(NewDirEntry, SetupDirEntryStrings, SetupDirEntryAnsiStrings);
  4446. raise;
  4447. end;
  4448. WriteDebugEntry(deDir, DirEntries.Count);
  4449. DirEntries.Add(NewDirEntry);
  4450. end;
  4451. function SpaceString(const S: String): String;
  4452. var
  4453. I: Integer;
  4454. begin
  4455. Result := '';
  4456. for I := 1 to Length(S) do begin
  4457. if S[I] = ' ' then Continue;
  4458. if Result <> '' then Result := Result + ' ';
  4459. Result := Result + S[I];
  4460. end;
  4461. end;
  4462. type
  4463. TMenuKeyCap = (mkcBkSp, mkcTab, mkcEsc, mkcEnter, mkcSpace, mkcPgUp,
  4464. mkcPgDn, mkcEnd, mkcHome, mkcLeft, mkcUp, mkcRight, mkcDown, mkcIns,
  4465. mkcDel, mkcShift, mkcCtrl, mkcAlt);
  4466. var
  4467. MenuKeyCaps: array[TMenuKeyCap] of string = (
  4468. SmkcBkSp, SmkcTab, SmkcEsc, SmkcEnter, SmkcSpace, SmkcPgUp,
  4469. SmkcPgDn, SmkcEnd, SmkcHome, SmkcLeft, SmkcUp, SmkcRight,
  4470. SmkcDown, SmkcIns, SmkcDel, SmkcShift, SmkcCtrl, SmkcAlt);
  4471. procedure TSetupCompiler.EnumIconsProc(const Line: PChar; const Ext: Integer);
  4472. function HotKeyToText(HotKey: Word): string;
  4473. function GetSpecialName(HotKey: Word): string;
  4474. var
  4475. ScanCode: Integer;
  4476. KeyName: array[0..255] of Char;
  4477. begin
  4478. Result := '';
  4479. ScanCode := MapVirtualKey(WordRec(HotKey).Lo, 0) shl 16;
  4480. if ScanCode <> 0 then
  4481. begin
  4482. GetKeyNameText(ScanCode, KeyName, SizeOf(KeyName));
  4483. if (KeyName[1] = #0) and (KeyName[0] <> #0) then
  4484. GetSpecialName := KeyName;
  4485. end;
  4486. end;
  4487. var
  4488. Name: string;
  4489. begin
  4490. case WordRec(HotKey).Lo of
  4491. $08, $09:
  4492. Name := MenuKeyCaps[TMenuKeyCap(Ord(mkcBkSp) + WordRec(HotKey).Lo - $08)];
  4493. $0D: Name := MenuKeyCaps[mkcEnter];
  4494. $1B: Name := MenuKeyCaps[mkcEsc];
  4495. $20..$28:
  4496. Name := MenuKeyCaps[TMenuKeyCap(Ord(mkcSpace) + WordRec(HotKey).Lo - $20)];
  4497. $2D..$2E:
  4498. Name := MenuKeyCaps[TMenuKeyCap(Ord(mkcIns) + WordRec(HotKey).Lo - $2D)];
  4499. $30..$39: Name := Chr(WordRec(HotKey).Lo - $30 + Ord('0'));
  4500. $41..$5A: Name := Chr(WordRec(HotKey).Lo - $41 + Ord('A'));
  4501. $60..$69: Name := Chr(WordRec(HotKey).Lo - $60 + Ord('0'));
  4502. $70..$87: Name := 'F' + IntToStr(WordRec(HotKey).Lo - $6F);
  4503. else
  4504. Name := GetSpecialName(HotKey);
  4505. end;
  4506. if Name <> '' then
  4507. begin
  4508. Result := '';
  4509. if HotKey and (HOTKEYF_SHIFT shl 8) <> 0 then Result := Result + MenuKeyCaps[mkcShift];
  4510. if HotKey and (HOTKEYF_CONTROL shl 8) <> 0 then Result := Result + MenuKeyCaps[mkcCtrl];
  4511. if HotKey and (HOTKEYF_ALT shl 8) <> 0 then Result := Result + MenuKeyCaps[mkcAlt];
  4512. Result := Result + Name;
  4513. end
  4514. else Result := '';
  4515. end;
  4516. function TextToHotKey(Text: string): Word;
  4517. function CompareFront(var Text: string; const Front: string): Boolean;
  4518. begin
  4519. Result := False;
  4520. if CompareText(Copy(Text, 1, Length(Front)), Front) = 0 then
  4521. begin
  4522. Result := True;
  4523. Delete(Text, 1, Length(Front));
  4524. end;
  4525. end;
  4526. var
  4527. Key: Word;
  4528. Shift: Word;
  4529. begin
  4530. Result := 0;
  4531. Shift := 0;
  4532. while True do
  4533. begin
  4534. if CompareFront(Text, MenuKeyCaps[mkcShift]) then Shift := Shift or HOTKEYF_SHIFT
  4535. else if CompareFront(Text, '^') then Shift := Shift or HOTKEYF_CONTROL
  4536. else if CompareFront(Text, MenuKeyCaps[mkcCtrl]) then Shift := Shift or HOTKEYF_CONTROL
  4537. else if CompareFront(Text, MenuKeyCaps[mkcAlt]) then Shift := Shift or HOTKEYF_ALT
  4538. else Break;
  4539. end;
  4540. if Text = '' then Exit;
  4541. for Key := $08 to $255 do { Copy range from table in HotKeyToText }
  4542. if AnsiCompareText(Text, HotKeyToText(Key)) = 0 then
  4543. begin
  4544. Result := Key or (Shift shl 8);
  4545. Exit;
  4546. end;
  4547. end;
  4548. type
  4549. TParam = (paFlags, paName, paFilename, paParameters, paWorkingDir, paHotKey,
  4550. paIconFilename, paIconIndex, paComment, paAppUserModelID, paAppUserModelToastActivatorCLSID,
  4551. paComponents, paTasks, paLanguages, paCheck, paBeforeInstall, paAfterInstall, paMinVersion,
  4552. paOnlyBelowVersion);
  4553. const
  4554. ParamIconsName = 'Name';
  4555. ParamIconsFilename = 'Filename';
  4556. ParamIconsParameters = 'Parameters';
  4557. ParamIconsWorkingDir = 'WorkingDir';
  4558. ParamIconsHotKey = 'HotKey';
  4559. ParamIconsIconFilename = 'IconFilename';
  4560. ParamIconsIconIndex = 'IconIndex';
  4561. ParamIconsComment = 'Comment';
  4562. ParamIconsAppUserModelID = 'AppUserModelID';
  4563. ParamIconsAppUserModelToastActivatorCLSID = 'AppUserModelToastActivatorCLSID';
  4564. ParamInfo: array[TParam] of TParamInfo = (
  4565. (Name: ParamCommonFlags; Flags: []),
  4566. (Name: ParamIconsName; Flags: [piRequired, piNoEmpty, piNoQuotes]),
  4567. (Name: ParamIconsFilename; Flags: [piRequired, piNoEmpty, piNoQuotes]),
  4568. (Name: ParamIconsParameters; Flags: []),
  4569. (Name: ParamIconsWorkingDir; Flags: [piNoQuotes]),
  4570. (Name: ParamIconsHotKey; Flags: []),
  4571. (Name: ParamIconsIconFilename; Flags: [piNoQuotes]),
  4572. (Name: ParamIconsIconIndex; Flags: []),
  4573. (Name: ParamIconsComment; Flags: []),
  4574. (Name: ParamIconsAppUserModelID; Flags: []),
  4575. (Name: ParamIconsAppUserModelToastActivatorCLSID; Flags: []),
  4576. (Name: ParamCommonComponents; Flags: []),
  4577. (Name: ParamCommonTasks; Flags: []),
  4578. (Name: ParamCommonLanguages; Flags: []),
  4579. (Name: ParamCommonCheck; Flags: []),
  4580. (Name: ParamCommonBeforeInstall; Flags: []),
  4581. (Name: ParamCommonAfterInstall; Flags: []),
  4582. (Name: ParamCommonMinVersion; Flags: []),
  4583. (Name: ParamCommonOnlyBelowVersion; Flags: []));
  4584. Flags: array[0..8] of PChar = (
  4585. 'uninsneveruninstall', 'runminimized', 'createonlyiffileexists',
  4586. 'useapppaths', 'closeonexit', 'dontcloseonexit', 'runmaximized',
  4587. 'excludefromshowinnewinstall', 'preventpinning');
  4588. var
  4589. Values: array[TParam] of TParamValue;
  4590. NewIconEntry: PSetupIconEntry;
  4591. S: String;
  4592. begin
  4593. ExtractParameters(Line, ParamInfo, Values);
  4594. NewIconEntry := AllocMem(SizeOf(TSetupIconEntry));
  4595. try
  4596. with NewIconEntry^ do begin
  4597. MinVersion := SetupHeader.MinVersion;
  4598. ShowCmd := SW_SHOWNORMAL;
  4599. { Flags }
  4600. while True do
  4601. case ExtractFlag(Values[paFlags].Data, Flags) of
  4602. -2: Break;
  4603. -1: AbortCompileParamError(SCompilerParamUnknownFlag2, ParamCommonFlags);
  4604. 0: Include(Options, ioUninsNeverUninstall);
  4605. 1: ShowCmd := SW_SHOWMINNOACTIVE;
  4606. 2: Include(Options, ioCreateOnlyIfFileExists);
  4607. 3: Include(Options, ioUseAppPaths);
  4608. 4: CloseOnExit := icYes;
  4609. 5: CloseOnExit := icNo;
  4610. 6: ShowCmd := SW_SHOWMAXIMIZED;
  4611. 7: Include(Options, ioExcludeFromShowInNewInstall);
  4612. 8: Include(Options, ioPreventPinning);
  4613. end;
  4614. { Name }
  4615. IconName := Values[paName].Data;
  4616. { Filename }
  4617. Filename := Values[paFilename].Data;
  4618. { Parameters }
  4619. Parameters := Values[paParameters].Data;
  4620. { WorkingDir }
  4621. WorkingDir := Values[paWorkingDir].Data;
  4622. { HotKey }
  4623. if Values[paHotKey].Found then begin
  4624. HotKey := TextToHotKey(Values[paHotKey].Data);
  4625. if HotKey = 0 then
  4626. AbortCompileParamError(SCompilerParamInvalid2, ParamIconsHotKey);
  4627. end;
  4628. { IconFilename }
  4629. IconFilename := Values[paIconFilename].Data;
  4630. { IconIndex }
  4631. if Values[paIconIndex].Found then begin
  4632. try
  4633. IconIndex := StrToInt(Values[paIconIndex].Data);
  4634. except
  4635. AbortCompileOnLine(SCompilerIconsIconIndexInvalid);
  4636. end;
  4637. end;
  4638. { Comment }
  4639. Comment := Values[paComment].Data;
  4640. { AppUserModel }
  4641. AppUserModelID := Values[paAppUserModelID].Data;
  4642. S := Values[paAppUserModelToastActivatorCLSID].Data;
  4643. if S <> '' then begin
  4644. AppUserModelToastActivatorCLSID := StringToGUID('{' + S + '}');
  4645. Include(Options, ioHasAppUserModelToastActivatorCLSID);
  4646. end;
  4647. { Common parameters }
  4648. ProcessExpressionParameter(ParamCommonComponents, Values[paComponents].Data, EvalComponentIdentifier, True, Components);
  4649. ProcessExpressionParameter(ParamCommonTasks, Values[paTasks].Data, EvalTaskIdentifier, True, Tasks);
  4650. ProcessExpressionParameter(ParamCommonLanguages, Values[paLanguages].Data, EvalLanguageIdentifier, False, Languages);
  4651. Check := Values[paCheck].Data;
  4652. BeforeInstall := Values[paBeforeInstall].Data;
  4653. AfterInstall := Values[paAfterInstall].Data;
  4654. ProcessMinVersionParameter(Values[paMinVersion], MinVersion);
  4655. ProcessOnlyBelowVersionParameter(Values[paOnlyBelowVersion], OnlyBelowVersion);
  4656. if Pos('"', IconName) <> 0 then
  4657. AbortCompileParamError(SCompilerParamNoQuotes2, ParamIconsName);
  4658. if PathPos('\', IconName) = 0 then
  4659. AbortCompileOnLine(SCompilerIconsNamePathNotSpecified);
  4660. if (IconIndex <> 0) and (IconFilename = '') then
  4661. IconFilename := Filename;
  4662. CheckCheckOrInstall(ParamCommonCheck, Check, cikCheck);
  4663. CheckCheckOrInstall(ParamCommonBeforeInstall, BeforeInstall, cikInstall);
  4664. CheckCheckOrInstall(ParamCommonAfterInstall, AfterInstall, cikInstall);
  4665. S := IconName;
  4666. if Copy(S, 1, 8) = '{group}\' then
  4667. Delete(S, 1, 8);
  4668. CheckConst(S, MinVersion, []);
  4669. CheckConst(Filename, MinVersion, []);
  4670. CheckConst(Parameters, MinVersion, []);
  4671. CheckConst(WorkingDir, MinVersion, []);
  4672. CheckConst(IconFilename, MinVersion, []);
  4673. CheckConst(Comment, MinVersion, []);
  4674. CheckConst(AppUserModelID, MinVersion, []);
  4675. end;
  4676. except
  4677. SEFreeRec(NewIconEntry, SetupIconEntryStrings, SetupIconEntryAnsiStrings);
  4678. raise;
  4679. end;
  4680. WriteDebugEntry(deIcon, IconEntries.Count);
  4681. IconEntries.Add(NewIconEntry);
  4682. end;
  4683. procedure TSetupCompiler.EnumINIProc(const Line: PChar; const Ext: Integer);
  4684. type
  4685. TParam = (paFlags, paFilename, paSection, paKey, paString, paComponents,
  4686. paTasks, paLanguages, paCheck, paBeforeInstall, paAfterInstall,
  4687. paMinVersion, paOnlyBelowVersion);
  4688. const
  4689. ParamIniFilename = 'Filename';
  4690. ParamIniSection = 'Section';
  4691. ParamIniKey = 'Key';
  4692. ParamIniString = 'String';
  4693. ParamInfo: array[TParam] of TParamInfo = (
  4694. (Name: ParamCommonFlags; Flags: []),
  4695. (Name: ParamIniFilename; Flags: [piRequired, piNoQuotes]),
  4696. (Name: ParamIniSection; Flags: [piRequired, piNoEmpty]),
  4697. (Name: ParamIniKey; Flags: [piNoEmpty]),
  4698. (Name: ParamIniString; Flags: []),
  4699. (Name: ParamCommonComponents; Flags: []),
  4700. (Name: ParamCommonTasks; Flags: []),
  4701. (Name: ParamCommonLanguages; Flags: []),
  4702. (Name: ParamCommonCheck; Flags: []),
  4703. (Name: ParamCommonBeforeInstall; Flags: []),
  4704. (Name: ParamCommonAfterInstall; Flags: []),
  4705. (Name: ParamCommonMinVersion; Flags: []),
  4706. (Name: ParamCommonOnlyBelowVersion; Flags: []));
  4707. Flags: array[0..3] of PChar = (
  4708. 'uninsdeleteentry', 'uninsdeletesection', 'createkeyifdoesntexist',
  4709. 'uninsdeletesectionifempty');
  4710. var
  4711. Values: array[TParam] of TParamValue;
  4712. NewIniEntry: PSetupIniEntry;
  4713. begin
  4714. ExtractParameters(Line, ParamInfo, Values);
  4715. NewIniEntry := AllocMem(SizeOf(TSetupIniEntry));
  4716. try
  4717. with NewIniEntry^ do begin
  4718. MinVersion := SetupHeader.MinVersion;
  4719. { Flags }
  4720. while True do
  4721. case ExtractFlag(Values[paFlags].Data, Flags) of
  4722. -2: Break;
  4723. -1: AbortCompileParamError(SCompilerParamUnknownFlag2, ParamCommonFlags);
  4724. 0: Include(Options, ioUninsDeleteEntry);
  4725. 1: Include(Options, ioUninsDeleteEntireSection);
  4726. 2: Include(Options, ioCreateKeyIfDoesntExist);
  4727. 3: Include(Options, ioUninsDeleteSectionIfEmpty);
  4728. end;
  4729. { Filename }
  4730. Filename := Values[paFilename].Data;
  4731. { Section }
  4732. Section := Values[paSection].Data;
  4733. { Key }
  4734. Entry := Values[paKey].Data;
  4735. { String }
  4736. if Values[paString].Found then begin
  4737. Value := Values[paString].Data;
  4738. Include(Options, ioHasValue);
  4739. end;
  4740. { Common parameters }
  4741. ProcessExpressionParameter(ParamCommonComponents, Values[paComponents].Data, EvalComponentIdentifier, True, Components);
  4742. ProcessExpressionParameter(ParamCommonTasks, Values[paTasks].Data, EvalTaskIdentifier, True, Tasks);
  4743. ProcessExpressionParameter(ParamCommonLanguages, Values[paLanguages].Data, EvalLanguageIdentifier, False, Languages);
  4744. Check := Values[paCheck].Data;
  4745. BeforeInstall := Values[paBeforeInstall].Data;
  4746. AfterInstall := Values[paAfterInstall].Data;
  4747. ProcessMinVersionParameter(Values[paMinVersion], MinVersion);
  4748. ProcessOnlyBelowVersionParameter(Values[paOnlyBelowVersion], OnlyBelowVersion);
  4749. if (ioUninsDeleteEntry in Options) and
  4750. (ioUninsDeleteEntireSection in Options) then
  4751. AbortCompileOnLineFmt(SCompilerParamErrorBadCombo2,
  4752. [ParamCommonFlags, 'uninsdeleteentry', 'uninsdeletesection']);
  4753. if (ioUninsDeleteEntireSection in Options) and
  4754. (ioUninsDeleteSectionIfEmpty in Options) then
  4755. AbortCompileOnLineFmt(SCompilerParamErrorBadCombo2,
  4756. [ParamCommonFlags, 'uninsdeletesection', 'uninsdeletesectionifempty']);
  4757. CheckCheckOrInstall(ParamCommonCheck, Check, cikCheck);
  4758. CheckCheckOrInstall(ParamCommonBeforeInstall, BeforeInstall, cikInstall);
  4759. CheckCheckOrInstall(ParamCommonAfterInstall, AfterInstall, cikInstall);
  4760. CheckConst(Filename, MinVersion, []);
  4761. CheckConst(Section, MinVersion, []);
  4762. CheckConst(Entry, MinVersion, []);
  4763. CheckConst(Value, MinVersion, []);
  4764. end;
  4765. except
  4766. SEFreeRec(NewIniEntry, SetupIniEntryStrings, SetupIniEntryAnsiStrings);
  4767. raise;
  4768. end;
  4769. WriteDebugEntry(deIni, IniEntries.Count);
  4770. IniEntries.Add(NewIniEntry);
  4771. end;
  4772. procedure TSetupCompiler.EnumRegistryProc(const Line: PChar; const Ext: Integer);
  4773. type
  4774. TParam = (paFlags, paRoot, paSubkey, paValueType, paValueName, paValueData,
  4775. paPermissions, paComponents, paTasks, paLanguages, paCheck, paBeforeInstall,
  4776. paAfterInstall, paMinVersion, paOnlyBelowVersion);
  4777. const
  4778. ParamRegistryRoot = 'Root';
  4779. ParamRegistrySubkey = 'Subkey';
  4780. ParamRegistryValueType = 'ValueType';
  4781. ParamRegistryValueName = 'ValueName';
  4782. ParamRegistryValueData = 'ValueData';
  4783. ParamRegistryPermissions = 'Permissions';
  4784. ParamInfo: array[TParam] of TParamInfo = (
  4785. (Name: ParamCommonFlags; Flags: []),
  4786. (Name: ParamRegistryRoot; Flags: [piRequired]),
  4787. (Name: ParamRegistrySubkey; Flags: [piRequired]),
  4788. (Name: ParamRegistryValueType; Flags: []),
  4789. (Name: ParamRegistryValueName; Flags: []),
  4790. (Name: ParamRegistryValueData; Flags: []),
  4791. (Name: ParamRegistryPermissions; Flags: []),
  4792. (Name: ParamCommonComponents; Flags: []),
  4793. (Name: ParamCommonTasks; Flags: []),
  4794. (Name: ParamCommonLanguages; Flags: []),
  4795. (Name: ParamCommonCheck; Flags: []),
  4796. (Name: ParamCommonBeforeInstall; Flags: []),
  4797. (Name: ParamCommonAfterInstall; Flags: []),
  4798. (Name: ParamCommonMinVersion; Flags: []),
  4799. (Name: ParamCommonOnlyBelowVersion; Flags: []));
  4800. Flags: array[0..9] of PChar = (
  4801. 'createvalueifdoesntexist', 'uninsdeletevalue', 'uninsdeletekey',
  4802. 'uninsdeletekeyifempty', 'uninsclearvalue', 'preservestringtype',
  4803. 'deletekey', 'deletevalue', 'noerror', 'dontcreatekey');
  4804. AccessMasks: array[0..2] of TNameAndAccessMask = (
  4805. (Name: 'full'; Mask: $F003F),
  4806. (Name: 'modify'; Mask: $3001F), { <- same access that Power Users get by default on HKLM\SOFTWARE }
  4807. (Name: 'read'; Mask: $20019));
  4808. function ConvertBinaryString(const S: String): String;
  4809. procedure Invalid;
  4810. begin
  4811. AbortCompileParamError(SCompilerParamInvalid2, ParamRegistryValueData);
  4812. end;
  4813. var
  4814. I: Integer;
  4815. C: Char;
  4816. B: Byte;
  4817. N: Integer;
  4818. procedure EndByte;
  4819. begin
  4820. case N of
  4821. 0: ;
  4822. 2: begin
  4823. Result := Result + Chr(B);
  4824. N := 0;
  4825. B := 0;
  4826. end;
  4827. else
  4828. Invalid;
  4829. end;
  4830. end;
  4831. begin
  4832. Result := '';
  4833. N := 0;
  4834. B := 0;
  4835. for I := 1 to Length(S) do begin
  4836. C := UpCase(S[I]);
  4837. case C of
  4838. ' ': EndByte;
  4839. '0'..'9': begin
  4840. Inc(N);
  4841. if N > 2 then
  4842. Invalid;
  4843. B := (B shl 4) or (Ord(C) - Ord('0'));
  4844. end;
  4845. 'A'..'F': begin
  4846. Inc(N);
  4847. if N > 2 then
  4848. Invalid;
  4849. B := (B shl 4) or (10 + Ord(C) - Ord('A'));
  4850. end;
  4851. else
  4852. Invalid;
  4853. end;
  4854. end;
  4855. EndByte;
  4856. end;
  4857. function ConvertDWordString(const S: String): String;
  4858. var
  4859. DW: DWORD;
  4860. E: Integer;
  4861. begin
  4862. Result := Trim(S);
  4863. { Only check if it doesn't start with a constant }
  4864. if (Result = '') or (Result[1] <> '{') then begin
  4865. Val(Result, DW, E);
  4866. if E <> 0 then
  4867. AbortCompileParamError(SCompilerParamInvalid2, ParamRegistryValueData);
  4868. { Not really necessary, but sanitize the value }
  4869. Result := Format('$%x', [DW]);
  4870. end;
  4871. end;
  4872. function ConvertQWordString(const S: String): String;
  4873. var
  4874. QW: Integer64;
  4875. begin
  4876. Result := Trim(S);
  4877. { Only check if it doesn't start with a constant }
  4878. if (Result = '') or (Result[1] <> '{') then begin
  4879. if not StrToInteger64(Result, QW) then
  4880. AbortCompileParamError(SCompilerParamInvalid2, ParamRegistryValueData);
  4881. { Not really necessary, but sanitize the value }
  4882. Result := Integer64ToStr(QW);
  4883. end;
  4884. end;
  4885. var
  4886. Values: array[TParam] of TParamValue;
  4887. NewRegistryEntry: PSetupRegistryEntry;
  4888. S, AData: String;
  4889. begin
  4890. ExtractParameters(Line, ParamInfo, Values);
  4891. NewRegistryEntry := AllocMem(SizeOf(TSetupRegistryEntry));
  4892. try
  4893. with NewRegistryEntry^ do begin
  4894. MinVersion := SetupHeader.MinVersion;
  4895. { Flags }
  4896. while True do
  4897. case ExtractFlag(Values[paFlags].Data, Flags) of
  4898. -2: Break;
  4899. -1: AbortCompileParamError(SCompilerParamUnknownFlag2, ParamCommonFlags);
  4900. 0: Include(Options, roCreateValueIfDoesntExist);
  4901. 1: Include(Options, roUninsDeleteValue);
  4902. 2: Include(Options, roUninsDeleteEntireKey);
  4903. 3: Include(Options, roUninsDeleteEntireKeyIfEmpty);
  4904. 4: Include(Options, roUninsClearValue);
  4905. 5: Include(Options, roPreserveStringType);
  4906. 6: Include(Options, roDeleteKey);
  4907. 7: Include(Options, roDeleteValue);
  4908. 8: Include(Options, roNoError);
  4909. 9: Include(Options, roDontCreateKey);
  4910. end;
  4911. { Root }
  4912. S := Uppercase(Trim(Values[paRoot].Data));
  4913. if Length(S) >= 2 then begin
  4914. { Check for '32' or '64' suffix }
  4915. if (S[Length(S)-1] = '3') and (S[Length(S)] = '2') then begin
  4916. Include(Options, ro32Bit);
  4917. SetLength(S, Length(S)-2);
  4918. end
  4919. else if (S[Length(S)-1] = '6') and (S[Length(S)] = '4') then begin
  4920. Include(Options, ro64Bit);
  4921. SetLength(S, Length(S)-2);
  4922. end;
  4923. end;
  4924. if S = 'HKA' then
  4925. RootKey := HKEY_AUTO
  4926. else if S = 'HKCR' then
  4927. RootKey := HKEY_CLASSES_ROOT
  4928. else if S = 'HKCU' then begin
  4929. UsedUserAreas.Add(S);
  4930. RootKey := HKEY_CURRENT_USER;
  4931. end else if S = 'HKLM' then
  4932. RootKey := HKEY_LOCAL_MACHINE
  4933. else if S = 'HKU' then
  4934. RootKey := HKEY_USERS
  4935. else if S = 'HKCC' then
  4936. RootKey := HKEY_CURRENT_CONFIG
  4937. else
  4938. AbortCompileParamError(SCompilerParamInvalid2, ParamRegistryRoot);
  4939. { Subkey }
  4940. if (Values[paSubkey].Data <> '') and (Values[paSubkey].Data[1] = '\') then
  4941. AbortCompileParamError(SCompilerParamNoPrecedingBackslash, ParamRegistrySubkey);
  4942. Subkey := Values[paSubkey].Data;
  4943. { ValueType }
  4944. if Values[paValueType].Found then begin
  4945. Values[paValueType].Data := Uppercase(Trim(Values[paValueType].Data));
  4946. if Values[paValueType].Data = 'NONE' then
  4947. Typ := rtNone
  4948. else if Values[paValueType].Data = 'STRING' then
  4949. Typ := rtString
  4950. else if Values[paValueType].Data = 'EXPANDSZ' then
  4951. Typ := rtExpandString
  4952. else if Values[paValueType].Data = 'MULTISZ' then
  4953. Typ := rtMultiString
  4954. else if Values[paValueType].Data = 'DWORD' then
  4955. Typ := rtDWord
  4956. else if Values[paValueType].Data = 'QWORD' then
  4957. Typ := rtQWord
  4958. else if Values[paValueType].Data = 'BINARY' then
  4959. Typ := rtBinary
  4960. else
  4961. AbortCompileParamError(SCompilerParamInvalid2, ParamRegistryValueType);
  4962. end;
  4963. { ValueName }
  4964. ValueName := Values[paValueName].Data;
  4965. { ValueData }
  4966. AData := Values[paValueData].Data;
  4967. { Permissions }
  4968. ProcessPermissionsParameter(Values[paPermissions].Data, AccessMasks,
  4969. PermissionsEntry);
  4970. { Common parameters }
  4971. ProcessExpressionParameter(ParamCommonComponents, Values[paComponents].Data, EvalComponentIdentifier, True, Components);
  4972. ProcessExpressionParameter(ParamCommonTasks, Values[paTasks].Data, EvalTaskIdentifier, True, Tasks);
  4973. ProcessExpressionParameter(ParamCommonLanguages, Values[paLanguages].Data, EvalLanguageIdentifier, False, Languages);
  4974. Check := Values[paCheck].Data;
  4975. BeforeInstall := Values[paBeforeInstall].Data;
  4976. AfterInstall := Values[paAfterInstall].Data;
  4977. ProcessMinVersionParameter(Values[paMinVersion], MinVersion);
  4978. ProcessOnlyBelowVersionParameter(Values[paOnlyBelowVersion], OnlyBelowVersion);
  4979. if (roUninsDeleteEntireKey in Options) and
  4980. (roUninsDeleteEntireKeyIfEmpty in Options) then
  4981. AbortCompileOnLineFmt(SCompilerParamErrorBadCombo2,
  4982. [ParamCommonFlags, 'uninsdeletekey', 'uninsdeletekeyifempty']);
  4983. if (roUninsDeleteEntireKey in Options) and
  4984. (roUninsClearValue in Options) then
  4985. AbortCompileOnLineFmt(SCompilerParamErrorBadCombo2,
  4986. [ParamCommonFlags, 'uninsclearvalue', 'uninsdeletekey']);
  4987. if (roUninsDeleteValue in Options) and
  4988. (roUninsDeleteEntireKey in Options) then
  4989. AbortCompileOnLineFmt(SCompilerParamErrorBadCombo2,
  4990. [ParamCommonFlags, 'uninsdeletevalue', 'uninsdeletekey']);
  4991. if (roUninsDeleteValue in Options) and
  4992. (roUninsClearValue in Options) then
  4993. AbortCompileOnLineFmt(SCompilerParamErrorBadCombo2,
  4994. [ParamCommonFlags, 'uninsdeletevalue', 'uninsclearvalue']);
  4995. { Safety checks }
  4996. if ((roUninsDeleteEntireKey in Options) or (roDeleteKey in Options)) and
  4997. (CompareText(Subkey, 'SYSTEM\CurrentControlSet\Control\Session Manager\Environment') = 0) then
  4998. AbortCompileOnLine(SCompilerRegistryDeleteKeyProhibited);
  4999. case Typ of
  5000. rtString, rtExpandString, rtMultiString:
  5001. ValueData := AData;
  5002. rtDWord:
  5003. ValueData := ConvertDWordString(AData);
  5004. rtQWord:
  5005. ValueData := ConvertQWordString(AData);
  5006. rtBinary:
  5007. ValueData := ConvertBinaryString(AData);
  5008. end;
  5009. CheckCheckOrInstall(ParamCommonCheck, Check, cikCheck);
  5010. CheckCheckOrInstall(ParamCommonBeforeInstall, BeforeInstall, cikInstall);
  5011. CheckCheckOrInstall(ParamCommonAfterInstall, AfterInstall, cikInstall);
  5012. CheckConst(Subkey, MinVersion, []);
  5013. CheckConst(ValueName, MinVersion, []);
  5014. case Typ of
  5015. rtString, rtExpandString:
  5016. CheckConst(ValueData, MinVersion, [acOldData]);
  5017. rtMultiString:
  5018. CheckConst(ValueData, MinVersion, [acOldData, acBreak]);
  5019. rtDWord:
  5020. CheckConst(ValueData, MinVersion, []);
  5021. end;
  5022. end;
  5023. except
  5024. SEFreeRec(NewRegistryEntry, SetupRegistryEntryStrings, SetupRegistryEntryAnsiStrings);
  5025. raise;
  5026. end;
  5027. WriteDebugEntry(deRegistry, RegistryEntries.Count);
  5028. RegistryEntries.Add(NewRegistryEntry);
  5029. end;
  5030. procedure TSetupCompiler.EnumDeleteProc(const Line: PChar; const Ext: Integer);
  5031. type
  5032. TParam = (paType, paName, paComponents, paTasks, paLanguages, paCheck,
  5033. paBeforeInstall, paAfterInstall, paMinVersion, paOnlyBelowVersion);
  5034. const
  5035. ParamDeleteType = 'Type';
  5036. ParamDeleteName = 'Name';
  5037. ParamInfo: array[TParam] of TParamInfo = (
  5038. (Name: ParamDeleteType; Flags: [piRequired]),
  5039. (Name: ParamDeleteName; Flags: [piRequired, piNoEmpty]),
  5040. (Name: ParamCommonComponents; Flags: []),
  5041. (Name: ParamCommonTasks; Flags: []),
  5042. (Name: ParamCommonLanguages; Flags: []),
  5043. (Name: ParamCommonCheck; Flags: []),
  5044. (Name: ParamCommonBeforeInstall; Flags: []),
  5045. (Name: ParamCommonAfterInstall; Flags: []),
  5046. (Name: ParamCommonMinVersion; Flags: []),
  5047. (Name: ParamCommonOnlyBelowVersion; Flags: []));
  5048. Types: array[TSetupDeleteType] of PChar = (
  5049. 'files', 'filesandordirs', 'dirifempty');
  5050. var
  5051. Values: array[TParam] of TParamValue;
  5052. NewDeleteEntry: PSetupDeleteEntry;
  5053. Valid: Boolean;
  5054. J: TSetupDeleteType;
  5055. begin
  5056. ExtractParameters(Line, ParamInfo, Values);
  5057. NewDeleteEntry := AllocMem(SizeOf(TSetupDeleteEntry));
  5058. try
  5059. with NewDeleteEntry^ do begin
  5060. MinVersion := SetupHeader.MinVersion;
  5061. { Type }
  5062. Values[paType].Data := Trim(Values[paType].Data);
  5063. Valid := False;
  5064. for J := Low(J) to High(J) do
  5065. if StrIComp(Types[J], PChar(Values[paType].Data)) = 0 then begin
  5066. DeleteType := J;
  5067. Valid := True;
  5068. Break;
  5069. end;
  5070. if not Valid then
  5071. AbortCompileParamError(SCompilerParamInvalid2, ParamDeleteType);
  5072. { Name }
  5073. Name := Values[paName].Data;
  5074. { Common parameters }
  5075. ProcessExpressionParameter(ParamCommonComponents, Values[paComponents].Data, EvalComponentIdentifier, True, Components);
  5076. ProcessExpressionParameter(ParamCommonTasks, Values[paTasks].Data, EvalTaskIdentifier, True, Tasks);
  5077. ProcessExpressionParameter(ParamCommonLanguages, Values[paLanguages].Data, EvalLanguageIdentifier, False, Languages);
  5078. Check := Values[paCheck].Data;
  5079. BeforeInstall := Values[paBeforeInstall].Data;
  5080. AfterInstall := Values[paAfterInstall].Data;
  5081. ProcessMinVersionParameter(Values[paMinVersion], MinVersion);
  5082. ProcessOnlyBelowVersionParameter(Values[paOnlyBelowVersion], OnlyBelowVersion);
  5083. CheckCheckOrInstall(ParamCommonCheck, Check, cikCheck);
  5084. CheckCheckOrInstall(ParamCommonBeforeInstall, BeforeInstall, cikInstall);
  5085. CheckCheckOrInstall(ParamCommonAfterInstall, AfterInstall, cikInstall);
  5086. CheckConst(Name, MinVersion, []);
  5087. end;
  5088. except
  5089. SEFreeRec(NewDeleteEntry, SetupDeleteEntryStrings, SetupDeleteEntryAnsiStrings);
  5090. raise;
  5091. end;
  5092. if Ext = 0 then begin
  5093. WriteDebugEntry(deInstallDelete, InstallDeleteEntries.Count);
  5094. InstallDeleteEntries.Add(NewDeleteEntry);
  5095. end
  5096. else begin
  5097. WriteDebugEntry(deUninstallDelete, UninstallDeleteEntries.Count);
  5098. UninstallDeleteEntries.Add(NewDeleteEntry);
  5099. end;
  5100. end;
  5101. procedure TSetupCompiler.EnumFilesProc(const Line: PChar; const Ext: Integer);
  5102. function EscapeBraces(const S: String): String;
  5103. { Changes all '{' to '{{' }
  5104. var
  5105. I: Integer;
  5106. begin
  5107. Result := S;
  5108. I := 1;
  5109. while I <= Length(Result) do begin
  5110. if Result[I] = '{' then begin
  5111. Insert('{', Result, I);
  5112. Inc(I);
  5113. end;
  5114. Inc(I);
  5115. end;
  5116. end;
  5117. type
  5118. TParam = (paFlags, paSource, paDestDir, paDestName, paCopyMode, paAttribs,
  5119. paPermissions, paFontInstall, paExcludes, paExternalSize, paStrongAssemblyName,
  5120. paComponents, paTasks, paLanguages, paCheck, paBeforeInstall, paAfterInstall,
  5121. paMinVersion, paOnlyBelowVersion);
  5122. const
  5123. ParamFilesSource = 'Source';
  5124. ParamFilesDestDir = 'DestDir';
  5125. ParamFilesDestName = 'DestName';
  5126. ParamFilesCopyMode = 'CopyMode';
  5127. ParamFilesAttribs = 'Attribs';
  5128. ParamFilesPermissions = 'Permissions';
  5129. ParamFilesFontInstall = 'FontInstall';
  5130. ParamFilesExcludes = 'Excludes';
  5131. ParamFilesExternalSize = 'ExternalSize';
  5132. ParamFilesStrongAssemblyName = 'StrongAssemblyName';
  5133. ParamInfo: array[TParam] of TParamInfo = (
  5134. (Name: ParamCommonFlags; Flags: []),
  5135. (Name: ParamFilesSource; Flags: [piRequired, piNoEmpty, piNoQuotes]),
  5136. (Name: ParamFilesDestDir; Flags: [piNoEmpty, piNoQuotes]),
  5137. (Name: ParamFilesDestName; Flags: [piNoEmpty, piNoQuotes]),
  5138. (Name: ParamFilesCopyMode; Flags: []),
  5139. (Name: ParamFilesAttribs; Flags: []),
  5140. (Name: ParamFilesPermissions; Flags: []),
  5141. (Name: ParamFilesFontInstall; Flags: [piNoEmpty]),
  5142. (Name: ParamFilesExcludes; Flags: []),
  5143. (Name: ParamFilesExternalSize; Flags: []),
  5144. (Name: ParamFilesStrongAssemblyName; Flags: [piNoEmpty]),
  5145. (Name: ParamCommonComponents; Flags: []),
  5146. (Name: ParamCommonTasks; Flags: []),
  5147. (Name: ParamCommonLanguages; Flags: []),
  5148. (Name: ParamCommonCheck; Flags: []),
  5149. (Name: ParamCommonBeforeInstall; Flags: []),
  5150. (Name: ParamCommonAfterInstall; Flags: []),
  5151. (Name: ParamCommonMinVersion; Flags: []),
  5152. (Name: ParamCommonOnlyBelowVersion; Flags: []));
  5153. Flags: array[0..39] of PChar = (
  5154. 'confirmoverwrite', 'uninsneveruninstall', 'isreadme', 'regserver',
  5155. 'sharedfile', 'restartreplace', 'deleteafterinstall',
  5156. 'comparetimestamp', 'fontisnttruetype', 'regtypelib', 'external',
  5157. 'skipifsourcedoesntexist', 'overwritereadonly', 'onlyifdestfileexists',
  5158. 'recursesubdirs', 'noregerror', 'allowunsafefiles', 'uninsrestartdelete',
  5159. 'onlyifdoesntexist', 'ignoreversion', 'promptifolder', 'dontcopy',
  5160. 'uninsremovereadonly', 'sortfilesbyextension', 'touch', 'replacesameversion',
  5161. 'noencryption', 'nocompression', 'dontverifychecksum',
  5162. 'uninsnosharedfileprompt', 'createallsubdirs', '32bit', '64bit',
  5163. 'solidbreak', 'setntfscompression', 'unsetntfscompression',
  5164. 'sortfilesbyname', 'gacinstall', 'sign', 'signonce');
  5165. AttribsFlags: array[0..3] of PChar = (
  5166. 'readonly', 'hidden', 'system', 'notcontentindexed');
  5167. AccessMasks: array[0..2] of TNameAndAccessMask = (
  5168. (Name: 'full'; Mask: $1F01FF),
  5169. (Name: 'modify'; Mask: $1301BF),
  5170. (Name: 'readexec'; Mask: $1200A9));
  5171. var
  5172. Values: array[TParam] of TParamValue;
  5173. NewFileEntry, PrevFileEntry: PSetupFileEntry;
  5174. NewFileLocationEntry: PSetupFileLocationEntry;
  5175. VersionNumbers: TFileVersionNumbers;
  5176. SourceWildcard, ADestDir, ADestName, AInstallFontName, AStrongAssemblyName: String;
  5177. AExcludes: TStringList;
  5178. ReadmeFile, ExternalFile, SourceIsWildcard, RecurseSubdirs,
  5179. AllowUnsafeFiles, Touch, NoCompression, NoEncryption, SolidBreak, Sign, SignOnce: Boolean;
  5180. type
  5181. PFileListRec = ^TFileListRec;
  5182. TFileListRec = record
  5183. Name: String;
  5184. Size: Integer64;
  5185. end;
  5186. PDirListRec = ^TDirListRec;
  5187. TDirListRec = record
  5188. Name: String;
  5189. end;
  5190. procedure CheckForUnsafeFile(const Filename, SourceFile: String;
  5191. const IsRegistered: Boolean);
  5192. { This generates errors on "unsafe files" }
  5193. const
  5194. UnsafeSysFiles: array[0..13] of String = (
  5195. 'ADVAPI32.DLL', 'COMCTL32.DLL', 'COMDLG32.DLL', 'GDI32.DLL',
  5196. 'KERNEL32.DLL', 'MSCOREE.DLL', 'RICHED32.DLL', 'SHDOCVW.DLL',
  5197. 'SHELL32.DLL', 'SHLWAPI.DLL', 'URLMON.DLL', 'USER32.DLL', 'UXTHEME.DLL',
  5198. 'WININET.DLL');
  5199. UnsafeNonSysRegFiles: array[0..5] of String = (
  5200. 'COMCAT.DLL', 'MSVBVM50.DLL', 'MSVBVM60.DLL', 'OLEAUT32.DLL',
  5201. 'OLEPRO32.DLL', 'STDOLE2.TLB');
  5202. var
  5203. SourceFileDir, SysWow64Dir: String;
  5204. I: Integer;
  5205. begin
  5206. if AllowUnsafeFiles then
  5207. Exit;
  5208. if ADestDir = '{sys}\' then begin
  5209. { Files that must NOT be deployed to the user's System directory }
  5210. { Any DLL deployed from system's own System directory }
  5211. if not ExternalFile and
  5212. (CompareText(PathExtractExt(Filename), '.DLL') = 0) then begin
  5213. SourceFileDir := PathExpand(PathExtractDir(SourceFile));
  5214. SysWow64Dir := GetSysWow64Dir;
  5215. if (PathCompare(SourceFileDir, GetSystemDir) = 0) or
  5216. ((SysWow64Dir <> '') and ((PathCompare(SourceFileDir, SysWow64Dir) = 0))) then
  5217. AbortCompileOnLine(SCompilerFilesSystemDirUsed);
  5218. end;
  5219. { CTL3D32.DLL }
  5220. if not ExternalFile and
  5221. (CompareText(Filename, 'CTL3D32.DLL') = 0) and
  5222. (NewFileEntry^.MinVersion.WinVersion <> 0) and
  5223. FileSizeAndCRCIs(SourceFile, 27136, $28A66C20) then
  5224. AbortCompileOnLineFmt(SCompilerFilesUnsafeFile, ['CTL3D32.DLL, Windows NT-specific version']);
  5225. { Remaining files }
  5226. for I := Low(UnsafeSysFiles) to High(UnsafeSysFiles) do
  5227. if CompareText(Filename, UnsafeSysFiles[I]) = 0 then
  5228. AbortCompileOnLineFmt(SCompilerFilesUnsafeFile, [UnsafeSysFiles[I]]);
  5229. end
  5230. else begin
  5231. { Files that MUST be deployed to the user's System directory }
  5232. if IsRegistered then
  5233. for I := Low(UnsafeNonSysRegFiles) to High(UnsafeNonSysRegFiles) do
  5234. if CompareText(Filename, UnsafeNonSysRegFiles[I]) = 0 then
  5235. AbortCompileOnLineFmt(SCompilerFilesSystemDirNotUsed, [UnsafeNonSysRegFiles[I]]);
  5236. end;
  5237. end;
  5238. function IsExcluded(Text: String): Boolean;
  5239. function CountBackslashes(S: PChar): Integer;
  5240. begin
  5241. Result := 0;
  5242. while True do begin
  5243. S := PathStrScan(S, '\');
  5244. if S = nil then
  5245. Break;
  5246. Inc(Result);
  5247. Inc(S);
  5248. end;
  5249. end;
  5250. var
  5251. I, J, TB, PB: Integer;
  5252. T, P, TStart, TEnd: PChar;
  5253. MatchFront: Boolean;
  5254. begin
  5255. if AExcludes.Count > 0 then begin
  5256. Text := PathLowercase(Text);
  5257. UniqueString(Text);
  5258. T := PChar(Text);
  5259. TB := CountBackslashes(T);
  5260. for I := 0 to AExcludes.Count-1 do begin
  5261. P := PChar(AExcludes[I]);
  5262. { Leading backslash in an exclude pattern means 'match at the front
  5263. instead of the end' }
  5264. MatchFront := False;
  5265. if P^ = '\' then begin
  5266. MatchFront := True;
  5267. Inc(P);
  5268. end;
  5269. PB := CountBackslashes(P);
  5270. { The text must contain at least as many backslashes as the pattern
  5271. for a match to be possible }
  5272. if TB >= PB then begin
  5273. TStart := T;
  5274. if not MatchFront then begin
  5275. { If matching at the end, advance TStart so that TStart and P point
  5276. to the same number of components }
  5277. for J := 1 to TB - PB do
  5278. TStart := PathStrScan(TStart, '\') + 1;
  5279. TEnd := nil;
  5280. end
  5281. else begin
  5282. { If matching at the front, clip T to the same number of
  5283. components as P }
  5284. TEnd := T;
  5285. for J := 1 to PB do
  5286. TEnd := PathStrScan(TEnd, '\') + 1;
  5287. TEnd := PathStrScan(TEnd, '\');
  5288. if Assigned(TEnd) then
  5289. TEnd^ := #0;
  5290. end;
  5291. if WildcardMatch(TStart, P) then begin
  5292. Result := True;
  5293. Exit;
  5294. end;
  5295. { Put back any backslash that was temporarily null'ed }
  5296. if Assigned(TEnd) then
  5297. TEnd^ := '\';
  5298. end;
  5299. end;
  5300. end;
  5301. Result := False;
  5302. end;
  5303. procedure AddToFileList(const FileList: TList; const Filename: String;
  5304. const SizeLo, SizeHi: LongWord);
  5305. var
  5306. Rec: PFileListRec;
  5307. begin
  5308. FileList.Expand;
  5309. New(Rec);
  5310. Rec.Name := Filename;
  5311. Rec.Size.Lo := SizeLo;
  5312. Rec.Size.Hi := SizeHi;
  5313. FileList.Add(Rec);
  5314. end;
  5315. procedure AddToDirList(const DirList: TList; const Dirname: String);
  5316. var
  5317. Rec: PDirListRec;
  5318. begin
  5319. DirList.Expand;
  5320. New(Rec);
  5321. Rec.Name := Dirname;
  5322. DirList.Add(Rec);
  5323. end;
  5324. procedure BuildFileList(const SearchBaseDir, SearchSubDir, SearchWildcard: String;
  5325. FileList, DirList: TList; CreateAllSubDirs: Boolean);
  5326. { Searches for any non excluded files matching "SearchBaseDir + SearchSubDir + SearchWildcard"
  5327. and adds them to FileList. }
  5328. var
  5329. SearchFullPath, FileName: String;
  5330. H: THandle;
  5331. FindData: TWin32FindData;
  5332. OldFileListCount, OldDirListCount: Integer;
  5333. begin
  5334. SearchFullPath := SearchBaseDir + SearchSubDir + SearchWildcard;
  5335. OldFileListCount := FileList.Count;
  5336. OldDirListCount := DirList.Count;
  5337. H := FindFirstFile(PChar(SearchFullPath), FindData);
  5338. if H <> INVALID_HANDLE_VALUE then begin
  5339. try
  5340. repeat
  5341. if FindData.dwFileAttributes and FILE_ATTRIBUTE_DIRECTORY <> 0 then
  5342. Continue;
  5343. if SourceIsWildcard then begin
  5344. if FindData.dwFileAttributes and FILE_ATTRIBUTE_HIDDEN <> 0 then
  5345. Continue;
  5346. FileName := FindData.cFileName;
  5347. end
  5348. else
  5349. FileName := SearchWildcard; { use the case specified in the script }
  5350. if IsExcluded(SearchSubDir + FileName) then
  5351. Continue;
  5352. AddToFileList(FileList, SearchSubDir + FileName, FindData.nFileSizeLow,
  5353. FindData.nFileSizeHigh);
  5354. CallIdleProc;
  5355. until not SourceIsWildcard or not FindNextFile(H, FindData);
  5356. finally
  5357. Windows.FindClose(H);
  5358. end;
  5359. end else
  5360. CallIdleProc;
  5361. if RecurseSubdirs then begin
  5362. H := FindFirstFile(PChar(SearchBaseDir + SearchSubDir + '*'), FindData);
  5363. if H <> INVALID_HANDLE_VALUE then begin
  5364. try
  5365. repeat
  5366. if (FindData.dwFileAttributes and FILE_ATTRIBUTE_DIRECTORY <> 0) and
  5367. (FindData.dwFileAttributes and FILE_ATTRIBUTE_HIDDEN = 0) and
  5368. (StrComp(FindData.cFileName, '.') <> 0) and
  5369. (StrComp(FindData.cFileName, '..') <> 0) and
  5370. not IsExcluded(SearchSubDir + FindData.cFileName) then
  5371. BuildFileList(SearchBaseDir, SearchSubDir + FindData.cFileName + '\',
  5372. SearchWildcard, FileList, DirList, CreateAllSubDirs);
  5373. until not FindNextFile(H, FindData);
  5374. finally
  5375. Windows.FindClose(H);
  5376. end;
  5377. end;
  5378. end;
  5379. if SearchSubDir <> '' then begin
  5380. { If both FileList and DirList didn't change size, this subdir won't be
  5381. created during install, so add it to DirList now if CreateAllSubDirs is set }
  5382. if CreateAllSubDirs and (FileList.Count = OldFileListCount) and
  5383. (DirList.Count = OldDirListCount) then
  5384. AddToDirList(DirList, SearchSubDir);
  5385. end;
  5386. end;
  5387. procedure ProcessFileList(const FileListBaseDir: String; FileList: TList);
  5388. var
  5389. FileListRec: PFileListRec;
  5390. CheckName: String;
  5391. SourceFile: String;
  5392. I, J: Integer;
  5393. NewRunEntry: PSetupRunEntry;
  5394. begin
  5395. for I := 0 to FileList.Count-1 do begin
  5396. FileListRec := FileList[I];
  5397. if NewFileEntry = nil then begin
  5398. NewFileEntry := AllocMem(SizeOf(TSetupFileEntry));
  5399. SEDuplicateRec(PrevFileEntry, NewFileEntry,
  5400. SizeOf(TSetupFileEntry), SetupFileEntryStrings, SetupFileEntryAnsiStrings);
  5401. end;
  5402. if Ext = 0 then begin
  5403. if ADestName = '' then begin
  5404. if not ExternalFile then
  5405. NewFileEntry^.DestName := ADestDir + EscapeBraces(FileListRec.Name)
  5406. else
  5407. { Don't append the filename to DestName on 'external' files;
  5408. it will be determined during installation }
  5409. NewFileEntry^.DestName := ADestDir;
  5410. end
  5411. else begin
  5412. if not ExternalFile then
  5413. NewFileEntry^.DestName := ADestDir + EscapeBraces(PathExtractPath(FileListRec.Name)) +
  5414. ADestName
  5415. else
  5416. NewFileEntry^.DestName := ADestDir + ADestName;
  5417. { ^ user is already required to escape '{' in DestName }
  5418. Include(NewFileEntry^.Options, foCustomDestName);
  5419. end;
  5420. end
  5421. else
  5422. NewFileEntry^.DestName := '';
  5423. SourceFile := FileListBaseDir + FileListRec.Name;
  5424. NewFileLocationEntry := nil;
  5425. if not ExternalFile then begin
  5426. if not DontMergeDuplicateFiles then begin
  5427. { See if the source filename is already in the list of files to
  5428. be compressed. If so, merge it. }
  5429. J := FileLocationEntryFilenames.CaseInsensitiveIndexOf(SourceFile);
  5430. if J <> -1 then begin
  5431. NewFileLocationEntry := FileLocationEntries[J];
  5432. NewFileEntry^.LocationEntry := J;
  5433. end;
  5434. end;
  5435. if NewFileLocationEntry = nil then begin
  5436. NewFileLocationEntry := AllocMem(SizeOf(TSetupFileLocationEntry));
  5437. SetupHeader.CompressMethod := CompressMethod;
  5438. FileLocationEntries.Add(NewFileLocationEntry);
  5439. FileLocationEntryFilenames.Add(SourceFile);
  5440. NewFileEntry^.LocationEntry := FileLocationEntries.Count-1;
  5441. if NewFileEntry^.FileType = ftUninstExe then
  5442. Include(NewFileLocationEntry^.Flags, foIsUninstExe);
  5443. Inc6464(TotalBytesToCompress, FileListRec.Size);
  5444. if SetupHeader.CompressMethod <> cmStored then
  5445. Include(NewFileLocationEntry^.Flags, foChunkCompressed);
  5446. if shEncryptionUsed in SetupHeader.Options then
  5447. Include(NewFileLocationEntry^.Flags, foChunkEncrypted);
  5448. if SolidBreak and UseSolidCompression then begin
  5449. Include(NewFileLocationEntry^.Flags, foSolidBreak);
  5450. { If the entry matches multiple files, it should only break prior
  5451. to compressing the first one }
  5452. SolidBreak := False;
  5453. end;
  5454. end;
  5455. if Touch then
  5456. Include(NewFileLocationEntry^.Flags, foApplyTouchDateTime);
  5457. if Sign then
  5458. Include(NewFileLocationEntry^.Flags, foSign)
  5459. else if SignOnce then
  5460. Include(NewFileLocationEntry^.Flags, foSignOnce);
  5461. { Note: "nocompression"/"noencryption" on one file makes all merged
  5462. copies uncompressed/unencrypted too }
  5463. if NoCompression then
  5464. Exclude(NewFileLocationEntry^.Flags, foChunkCompressed);
  5465. if NoEncryption then
  5466. Exclude(NewFileLocationEntry^.Flags, foChunkEncrypted);
  5467. end
  5468. else begin
  5469. NewFileEntry^.SourceFilename := SourceFile;
  5470. NewFileEntry^.LocationEntry := -1;
  5471. end;
  5472. { Read version info }
  5473. if not ExternalFile and not(foIgnoreVersion in NewFileEntry^.Options) and
  5474. (NewFileLocationEntry^.Flags * [foVersionInfoValid, foVersionInfoNotValid] = []) then begin
  5475. AddStatus(Format(SCompilerStatusFilesVerInfo, [SourceFile]));
  5476. if GetVersionNumbers(SourceFile, VersionNumbers) then begin
  5477. NewFileLocationEntry^.FileVersionMS := VersionNumbers.MS;
  5478. NewFileLocationEntry^.FileVersionLS := VersionNumbers.LS;
  5479. Include(NewFileLocationEntry^.Flags, foVersionInfoValid);
  5480. end
  5481. else
  5482. Include(NewFileLocationEntry^.Flags, foVersionInfoNotValid);
  5483. end;
  5484. { Safety checks }
  5485. if Ext = 0 then begin
  5486. if ADestName <> '' then
  5487. CheckName := ADestName
  5488. else
  5489. CheckName := PathExtractName(FileListRec.Name);
  5490. CheckForUnsafeFile(CheckName, SourceFile,
  5491. (foRegisterServer in NewFileEntry^.Options) or
  5492. (foRegisterTypeLib in NewFileEntry^.Options));
  5493. if (ADestDir = '{sys}\') and (foIgnoreVersion in NewFileEntry^.Options) and
  5494. (CompareText(PathExtractExt(CheckName), '.scr') <> 0) then
  5495. WarningsList.Add(Format(SCompilerFilesIgnoreVersionUsedUnsafely, [CheckName]));
  5496. end;
  5497. if ReadmeFile then begin
  5498. NewRunEntry := AllocMem(Sizeof(TSetupRunEntry));
  5499. NewRunEntry.Name := NewFileEntry.DestName;
  5500. NewRunEntry.Components := NewFileEntry.Components;
  5501. NewRunEntry.Tasks := NewFileEntry.Tasks;
  5502. NewRunEntry.Languages := NewFileEntry.Languages;
  5503. NewRunEntry.Check := NewFileEntry.Check;
  5504. NewRunEntry.BeforeInstall := '';
  5505. NewRunEntry.AfterInstall := '';
  5506. NewRunEntry.MinVersion := NewFileEntry.MinVersion;
  5507. NewRunEntry.OnlyBelowVersion := NewFileEntry.OnlyBelowVersion;
  5508. NewRunEntry.Options := [roShellExec, roSkipIfDoesntExist, roPostInstall,
  5509. roSkipIfSilent, roRunAsOriginalUser];
  5510. NewRunEntry.ShowCmd := SW_SHOWNORMAL;
  5511. NewRunEntry.Wait := rwNoWait;
  5512. NewRunEntry.Verb := '';
  5513. RunEntries.Insert(0, NewRunEntry);
  5514. ShiftDebugEntryIndexes(deRun); { because we inserted at the front }
  5515. end;
  5516. WriteDebugEntry(deFile, FileEntries.Count);
  5517. FileEntries.Expand;
  5518. PrevFileEntry := NewFileEntry;
  5519. { nil before adding so there's no chance it could ever be double-freed }
  5520. NewFileEntry := nil;
  5521. FileEntries.Add(PrevFileEntry);
  5522. CallIdleProc;
  5523. end;
  5524. end;
  5525. procedure SortFileList(FileList: TList; L: Integer; const R: Integer;
  5526. const ByExtension, ByName: Boolean);
  5527. function Compare(const F1, F2: PFileListRec): Integer;
  5528. function ComparePathStr(P1, P2: PChar): Integer;
  5529. { Like CompareStr, but sorts backslashes correctly ('A\B' < 'AB\B') }
  5530. var
  5531. C1, C2: Char;
  5532. begin
  5533. repeat
  5534. C1 := P1^;
  5535. if C1 = '\' then
  5536. C1 := #1;
  5537. C2 := P2^;
  5538. if C2 = '\' then
  5539. C2 := #1;
  5540. Result := Ord(C1) - Ord(C2);
  5541. if Result <> 0 then
  5542. Break;
  5543. if C1 = #0 then
  5544. Break;
  5545. Inc(P1);
  5546. Inc(P2);
  5547. until False;
  5548. end;
  5549. var
  5550. S1, S2: String;
  5551. begin
  5552. { Optimization: First check if we were passed the same string }
  5553. if Pointer(F1.Name) = Pointer(F2.Name) then begin
  5554. Result := 0;
  5555. Exit;
  5556. end;
  5557. S1 := AnsiUppercase(F1.Name); { uppercase to mimic NTFS's sort order }
  5558. S2 := AnsiUppercase(F2.Name);
  5559. if ByExtension then
  5560. Result := CompareStr(PathExtractExt(S1), PathExtractExt(S2))
  5561. else
  5562. Result := 0;
  5563. if ByName and (Result = 0) then
  5564. Result := CompareStr(PathExtractName(S1), PathExtractName(S2));
  5565. if Result = 0 then begin
  5566. { To avoid randomness in the sorting, sort by path and then name }
  5567. Result := ComparePathStr(PChar(PathExtractPath(S1)),
  5568. PChar(PathExtractPath(S2)));
  5569. if Result = 0 then
  5570. Result := CompareStr(S1, S2);
  5571. end;
  5572. end;
  5573. var
  5574. I, J: Integer;
  5575. P: PFileListRec;
  5576. begin
  5577. repeat
  5578. I := L;
  5579. J := R;
  5580. P := FileList[(L + R) shr 1];
  5581. repeat
  5582. while Compare(FileList[I], P) < 0 do
  5583. Inc(I);
  5584. while Compare(FileList[J], P) > 0 do
  5585. Dec(J);
  5586. if I <= J then begin
  5587. FileList.Exchange(I, J);
  5588. Inc(I);
  5589. Dec(J);
  5590. end;
  5591. until I > J;
  5592. if L < J then
  5593. SortFileList(FileList, L, J, ByExtension, ByName);
  5594. L := I;
  5595. until I >= R;
  5596. end;
  5597. procedure ProcessDirList(DirList: TList);
  5598. var
  5599. DirListRec: PDirListRec;
  5600. NewDirEntry: PSetupDirEntry;
  5601. BaseFileEntry: PSetupFileEntry;
  5602. I: Integer;
  5603. begin
  5604. if NewFileEntry <> nil then
  5605. { If NewFileEntry is still assigned it means ProcessFileList didn't
  5606. process any files (i.e. only directories were matched) }
  5607. BaseFileEntry := NewFileEntry
  5608. else
  5609. BaseFileEntry := PrevFileEntry;
  5610. if not(foDontCopy in BaseFileEntry.Options) then begin
  5611. for I := 0 to DirList.Count-1 do begin
  5612. DirListRec := DirList[I];
  5613. NewDirEntry := AllocMem(Sizeof(TSetupDirEntry));
  5614. NewDirEntry.DirName := ADestDir + EscapeBraces(DirListRec.Name);
  5615. NewDirEntry.Components := BaseFileEntry.Components;
  5616. NewDirEntry.Tasks := BaseFileEntry.Tasks;
  5617. NewDirEntry.Languages := BaseFileEntry.Languages;
  5618. NewDirEntry.Check := BaseFileEntry.Check;
  5619. NewDirEntry.BeforeInstall := '';
  5620. NewDirEntry.AfterInstall := '';
  5621. NewDirEntry.MinVersion := BaseFileEntry.MinVersion;
  5622. NewDirEntry.OnlyBelowVersion := BaseFileEntry.OnlyBelowVersion;
  5623. NewDirEntry.Attribs := 0;
  5624. NewDirEntry.PermissionsEntry := -1;
  5625. NewDirEntry.Options := [];
  5626. DirEntries.Add(NewDirEntry);
  5627. end;
  5628. end;
  5629. end;
  5630. var
  5631. FileList, DirList: TList;
  5632. SortFilesByExtension, SortFilesByName: Boolean;
  5633. I: Integer;
  5634. begin
  5635. CallIdleProc;
  5636. if Ext = 0 then
  5637. ExtractParameters(Line, ParamInfo, Values);
  5638. AExcludes := TStringList.Create();
  5639. try
  5640. PrevFileEntry := nil;
  5641. NewFileEntry := AllocMem(SizeOf(TSetupFileEntry));
  5642. try
  5643. with NewFileEntry^ do begin
  5644. MinVersion := SetupHeader.MinVersion;
  5645. PermissionsEntry := -1;
  5646. ADestName := '';
  5647. ADestDir := '';
  5648. AInstallFontName := '';
  5649. AStrongAssemblyName := '';
  5650. ReadmeFile := False;
  5651. ExternalFile := False;
  5652. RecurseSubdirs := False;
  5653. AllowUnsafeFiles := False;
  5654. Touch := False;
  5655. SortFilesByExtension := False;
  5656. NoCompression := False;
  5657. NoEncryption := False;
  5658. SolidBreak := False;
  5659. ExternalSize.Hi := 0;
  5660. ExternalSize.Lo := 0;
  5661. SortFilesByName := False;
  5662. Sign := False;
  5663. SignOnce := False;
  5664. case Ext of
  5665. 0: begin
  5666. { Flags }
  5667. while True do
  5668. case ExtractFlag(Values[paFlags].Data, Flags) of
  5669. -2: Break;
  5670. -1: AbortCompileParamError(SCompilerParamUnknownFlag2, ParamCommonFlags);
  5671. 0: Include(Options, foConfirmOverwrite);
  5672. 1: Include(Options, foUninsNeverUninstall);
  5673. 2: ReadmeFile := True;
  5674. 3: Include(Options, foRegisterServer);
  5675. 4: Include(Options, foSharedFile);
  5676. 5: Include(Options, foRestartReplace);
  5677. 6: Include(Options, foDeleteAfterInstall);
  5678. 7: Include(Options, foCompareTimeStamp);
  5679. 8: Include(Options, foFontIsntTrueType);
  5680. 9: Include(Options, foRegisterTypeLib);
  5681. 10: ExternalFile := True;
  5682. 11: Include(Options, foSkipIfSourceDoesntExist);
  5683. 12: Include(Options, foOverwriteReadOnly);
  5684. 13: Include(Options, foOnlyIfDestFileExists);
  5685. 14: RecurseSubdirs := True;
  5686. 15: Include(Options, foNoRegError);
  5687. 16: AllowUnsafeFiles := True;
  5688. 17: Include(Options, foUninsRestartDelete);
  5689. 18: Include(Options, foOnlyIfDoesntExist);
  5690. 19: Include(Options, foIgnoreVersion);
  5691. 20: Include(Options, foPromptIfOlder);
  5692. 21: Include(Options, foDontCopy);
  5693. 22: Include(Options, foUninsRemoveReadOnly);
  5694. 23: SortFilesByExtension := True;
  5695. 24: Touch := True;
  5696. 25: Include(Options, foReplaceSameVersionIfContentsDiffer);
  5697. 26: NoEncryption := True;
  5698. 27: NoCompression := True;
  5699. 28: Include(Options, foDontVerifyChecksum);
  5700. 29: Include(Options, foUninsNoSharedFilePrompt);
  5701. 30: Include(Options, foCreateAllSubDirs);
  5702. 31: Include(Options, fo32Bit);
  5703. 32: Include(Options, fo64Bit);
  5704. 33: SolidBreak := True;
  5705. 34: Include(Options, foSetNTFSCompression);
  5706. 35: Include(Options, foUnsetNTFSCompression);
  5707. 36: SortFilesByName := True;
  5708. 37: Include(Options, foGacInstall);
  5709. 38: Sign := True;
  5710. 39: SignOnce := True;
  5711. end;
  5712. { Source }
  5713. SourceWildcard := Values[paSource].Data;
  5714. { DestDir }
  5715. if Values[paDestDir].Found then
  5716. ADestDir := Values[paDestDir].Data
  5717. else begin
  5718. if foDontCopy in Options then
  5719. { DestDir is optional when the 'dontcopy' flag is used }
  5720. ADestDir := '{tmp}'
  5721. else
  5722. AbortCompileParamError(SCompilerParamNotSpecified, ParamFilesDestDir);
  5723. end;
  5724. { DestName }
  5725. if ConstPos('\', Values[paDestName].Data) <> 0 then
  5726. AbortCompileParamError(SCompilerParamNoBackslash, ParamFilesDestName);
  5727. ADestName := Values[paDestName].Data;
  5728. { CopyMode }
  5729. if Values[paCopyMode].Found then begin
  5730. Values[paCopyMode].Data := Trim(Values[paCopyMode].Data);
  5731. if CompareText(Values[paCopyMode].Data, 'normal') = 0 then begin
  5732. Include(Options, foPromptIfOlder);
  5733. WarningsList.Add(Format(SCompilerFilesWarningCopyMode,
  5734. ['normal', 'promptifolder', 'promptifolder']));
  5735. end
  5736. else if CompareText(Values[paCopyMode].Data, 'onlyifdoesntexist') = 0 then begin
  5737. Include(Options, foOnlyIfDoesntExist);
  5738. WarningsList.Add(Format(SCompilerFilesWarningCopyMode,
  5739. ['onlyifdoesntexist', 'onlyifdoesntexist',
  5740. 'onlyifdoesntexist']));
  5741. end
  5742. else if CompareText(Values[paCopyMode].Data, 'alwaysoverwrite') = 0 then begin
  5743. Include(Options, foIgnoreVersion);
  5744. WarningsList.Add(Format(SCompilerFilesWarningCopyMode,
  5745. ['alwaysoverwrite', 'ignoreversion', 'ignoreversion']));
  5746. end
  5747. else if CompareText(Values[paCopyMode].Data, 'alwaysskipifsameorolder') = 0 then begin
  5748. WarningsList.Add(SCompilerFilesWarningASISOO);
  5749. end
  5750. else if CompareText(Values[paCopyMode].Data, 'dontcopy') = 0 then begin
  5751. Include(Options, foDontCopy);
  5752. WarningsList.Add(Format(SCompilerFilesWarningCopyMode,
  5753. ['dontcopy', 'dontcopy', 'dontcopy']));
  5754. end
  5755. else
  5756. AbortCompileParamError(SCompilerParamInvalid2, ParamFilesCopyMode);
  5757. end;
  5758. { Attribs }
  5759. while True do
  5760. case ExtractFlag(Values[paAttribs].Data, AttribsFlags) of
  5761. -2: Break;
  5762. -1: AbortCompileParamError(SCompilerParamUnknownFlag2, ParamFilesAttribs);
  5763. 0: Attribs := Attribs or FILE_ATTRIBUTE_READONLY;
  5764. 1: Attribs := Attribs or FILE_ATTRIBUTE_HIDDEN;
  5765. 2: Attribs := Attribs or FILE_ATTRIBUTE_SYSTEM;
  5766. 3: Attribs := Attribs or FILE_ATTRIBUTE_NOT_CONTENT_INDEXED;
  5767. end;
  5768. { Permissions }
  5769. ProcessPermissionsParameter(Values[paPermissions].Data, AccessMasks,
  5770. PermissionsEntry);
  5771. { FontInstall }
  5772. AInstallFontName := Values[paFontInstall].Data;
  5773. { StrongAssemblyName }
  5774. AStrongAssemblyName := Values[paStrongAssemblyName].Data;
  5775. { Excludes }
  5776. ProcessWildcardsParameter(Values[paExcludes].Data, AExcludes, SCompilerFilesExcludeTooLong);
  5777. { ExternalSize }
  5778. if Values[paExternalSize].Found then begin
  5779. if not ExternalFile then
  5780. AbortCompileOnLine(SCompilerFilesCantHaveNonExternalExternalSize);
  5781. if not StrToInteger64(Values[paExternalSize].Data, ExternalSize) then
  5782. AbortCompileParamError(SCompilerParamInvalid2, ParamFilesExternalSize);
  5783. Include(Options, foExternalSizePreset);
  5784. end;
  5785. { Common parameters }
  5786. ProcessExpressionParameter(ParamCommonComponents, Values[paComponents].Data, EvalComponentIdentifier, True, Components);
  5787. ProcessExpressionParameter(ParamCommonTasks, Values[paTasks].Data, EvalTaskIdentifier, True, Tasks);
  5788. ProcessExpressionParameter(ParamCommonLanguages, Values[paLanguages].Data, EvalLanguageIdentifier, False, Languages);
  5789. Check := Values[paCheck].Data;
  5790. BeforeInstall := Values[paBeforeInstall].Data;
  5791. AfterInstall := Values[paAfterInstall].Data;
  5792. ProcessMinVersionParameter(Values[paMinVersion], MinVersion);
  5793. ProcessOnlyBelowVersionParameter(Values[paOnlyBelowVersion], OnlyBelowVersion);
  5794. end;
  5795. 1: begin
  5796. SourceWildcard := '';
  5797. FileType := ftUninstExe;
  5798. { Ordinary hash comparison on unins*.exe won't really work since
  5799. Setup modifies the file after extracting it. Force same
  5800. version to always be overwritten by including the special
  5801. foOverwriteSameVersion option. }
  5802. Options := [foOverwriteSameVersion];
  5803. ExternalFile := True;
  5804. end;
  5805. end;
  5806. if (ADestDir = '{tmp}') or (Copy(ADestDir, 1, 4) = '{tmp}\') then
  5807. Include(Options, foDeleteAfterInstall);
  5808. if foDeleteAfterInstall in Options then begin
  5809. if foRestartReplace in Options then
  5810. AbortCompileOnLineFmt(SCompilerFilesTmpBadFlag, ['restartreplace']);
  5811. if foUninsNeverUninstall in Options then
  5812. AbortCompileOnLineFmt(SCompilerFilesTmpBadFlag, ['uninsneveruninstall']);
  5813. if foRegisterServer in Options then
  5814. AbortCompileOnLineFmt(SCompilerFilesTmpBadFlag, ['regserver']);
  5815. if foRegisterTypeLib in Options then
  5816. AbortCompileOnLineFmt(SCompilerFilesTmpBadFlag, ['regtypelib']);
  5817. if foSharedFile in Options then
  5818. AbortCompileOnLineFmt(SCompilerFilesTmpBadFlag, ['sharedfile']);
  5819. if foGacInstall in Options then
  5820. AbortCompileOnLineFmt(SCompilerFilesTmpBadFlag, ['gacinstall']);
  5821. Include(Options, foUninsNeverUninstall);
  5822. end;
  5823. if (fo32Bit in Options) and (fo64Bit in Options) then
  5824. AbortCompileOnLineFmt(SCompilerParamErrorBadCombo2,
  5825. [ParamCommonFlags, '32bit', '64bit']);
  5826. if AInstallFontName <> '' then begin
  5827. if not(foFontIsntTrueType in Options) then
  5828. AInstallFontName := AInstallFontName + ' (TrueType)';
  5829. InstallFontName := AInstallFontName;
  5830. end;
  5831. if (foGacInstall in Options) and (AStrongAssemblyName = '') then
  5832. AbortCompileOnLine(SCompilerFilesStrongAssemblyNameMustBeSpecified);
  5833. if AStrongAssemblyName <> '' then
  5834. StrongAssemblyName := AStrongAssemblyName;
  5835. if not NoCompression and (foDontVerifyChecksum in Options) then
  5836. AbortCompileOnLineFmt(SCompilerParamFlagMissing, ['nocompression', 'dontverifychecksum']);
  5837. if Sign and SignOnce then
  5838. AbortCompileOnLineFmt(SCompilerParamErrorBadCombo2,
  5839. [ParamCommonFlags, 'sign', 'signonce']);
  5840. if ExternalFile then begin
  5841. if (AExcludes.Count > 0) then
  5842. AbortCompileOnLine(SCompilerFilesCantHaveExternalExclude)
  5843. else if Sign then
  5844. AbortCompileOnLineFmt(SCompilerParamErrorBadCombo2,
  5845. [ParamCommonFlags, 'external', 'sign'])
  5846. else if SignOnce then
  5847. AbortCompileOnLineFmt(SCompilerParamErrorBadCombo2,
  5848. [ParamCommonFlags, 'external', 'signonce']);
  5849. end;
  5850. if SignTools.Count = 0 then begin
  5851. Sign := False;
  5852. SignOnce := False;
  5853. end;
  5854. if not RecurseSubdirs and (foCreateAllSubDirs in Options) then
  5855. AbortCompileOnLineFmt(SCompilerParamFlagMissing, ['recursesubdirs', 'createallsubdirs']);
  5856. if (foSetNTFSCompression in Options) and
  5857. (foUnsetNTFSCompression in Options) then
  5858. AbortCompileOnLineFmt(SCompilerParamErrorBadCombo2,
  5859. [ParamCommonFlags, 'setntfscompression', 'unsetntfscompression']);
  5860. if (foSharedFile in Options) and
  5861. (Copy(ADestDir, 1, Length('{syswow64}')) = '{syswow64}') then
  5862. WarningsList.Add(SCompilerFilesWarningSharedFileSysWow64);
  5863. SourceIsWildcard := IsWildcard(SourceWildcard);
  5864. if ExternalFile then begin
  5865. if RecurseSubdirs then
  5866. Include(Options, foRecurseSubDirsExternal);
  5867. CheckConst(SourceWildcard, MinVersion, []);
  5868. end;
  5869. if (ADestName <> '') and SourceIsWildcard then
  5870. AbortCompileOnLine(SCompilerFilesDestNameCantBeSpecified);
  5871. CheckConst(ADestDir, MinVersion, []);
  5872. ADestDir := AddBackslash(ADestDir);
  5873. CheckConst(ADestName, MinVersion, []);
  5874. if not ExternalFile then
  5875. SourceWildcard := PrependSourceDirName(SourceWildcard);
  5876. CheckCheckOrInstall(ParamCommonCheck, Check, cikCheck);
  5877. CheckCheckOrInstall(ParamCommonBeforeInstall, BeforeInstall, cikInstall);
  5878. CheckCheckOrInstall(ParamCommonAfterInstall, AfterInstall, cikInstall);
  5879. end;
  5880. FileList := TLowFragList.Create();
  5881. DirList := TLowFragList.Create();
  5882. try
  5883. if not ExternalFile then begin
  5884. BuildFileList(PathExtractPath(SourceWildcard), '', PathExtractName(SourceWildcard), FileList, DirList, foCreateAllSubDirs in NewFileEntry.Options);
  5885. if FileList.Count > 1 then
  5886. SortFileList(FileList, 0, FileList.Count-1, SortFilesByExtension, SortFilesByName);
  5887. end else
  5888. AddToFileList(FileList, SourceWildcard, 0, 0);
  5889. if FileList.Count > 0 then begin
  5890. if not ExternalFile then
  5891. ProcessFileList(PathExtractPath(SourceWildcard), FileList)
  5892. else
  5893. ProcessFileList('', FileList);
  5894. end;
  5895. if DirList.Count > 0 then begin
  5896. { Dirs found that need to be created. Can only happen if not external. }
  5897. ProcessDirList(DirList);
  5898. end;
  5899. if (FileList.Count = 0) and (DirList.Count = 0) then begin
  5900. { Nothing found. Can only happen if not external. }
  5901. if not(foSkipIfSourceDoesntExist in NewFileEntry^.Options) then begin
  5902. if SourceIsWildcard then
  5903. AbortCompileOnLineFmt(SCompilerFilesWildcardNotMatched, [SourceWildcard])
  5904. else
  5905. AbortCompileOnLineFmt(SCompilerSourceFileDoesntExist, [SourceWildcard]);
  5906. end;
  5907. end;
  5908. finally
  5909. for I := DirList.Count-1 downto 0 do
  5910. Dispose(PDirListRec(DirList[I]));
  5911. DirList.Free();
  5912. for I := FileList.Count-1 downto 0 do
  5913. Dispose(PFileListRec(FileList[I]));
  5914. FileList.Free();
  5915. end;
  5916. finally
  5917. { If NewFileEntry is still assigned at this point, either an exception
  5918. occurred or no files were matched }
  5919. SEFreeRec(NewFileEntry, SetupFileEntryStrings, SetupFileEntryAnsiStrings);
  5920. end;
  5921. finally
  5922. AExcludes.Free();
  5923. end;
  5924. end;
  5925. procedure UpdateTimeStamp(H: THandle);
  5926. var
  5927. FT: TFileTime;
  5928. begin
  5929. GetSystemTimeAsFileTime(FT);
  5930. SetFileTime(H, nil, nil, @FT);
  5931. end;
  5932. procedure TSetupCompiler.EnumRunProc(const Line: PChar; const Ext: Integer);
  5933. type
  5934. TParam = (paFlags, paFilename, paParameters, paWorkingDir, paRunOnceId,
  5935. paDescription, paStatusMsg, paVerb, paComponents, paTasks, paLanguages,
  5936. paCheck, paBeforeInstall, paAfterInstall, paMinVersion, paOnlyBelowVersion);
  5937. const
  5938. ParamRunFilename = 'Filename';
  5939. ParamRunParameters = 'Parameters';
  5940. ParamRunWorkingDir = 'WorkingDir';
  5941. ParamRunRunOnceId = 'RunOnceId';
  5942. ParamRunDescription = 'Description';
  5943. ParamRunStatusMsg = 'StatusMsg';
  5944. ParamRunVerb = 'Verb';
  5945. ParamInfo: array[TParam] of TParamInfo = (
  5946. (Name: ParamCommonFlags; Flags: []),
  5947. (Name: ParamRunFilename; Flags: [piRequired, piNoEmpty, piNoQuotes]),
  5948. (Name: ParamRunParameters; Flags: []),
  5949. (Name: ParamRunWorkingDir; Flags: []),
  5950. (Name: ParamRunRunOnceId; Flags: []),
  5951. (Name: ParamRunDescription; Flags: []),
  5952. (Name: ParamRunStatusMsg; Flags: []),
  5953. (Name: ParamRunVerb; Flags: []),
  5954. (Name: ParamCommonComponents; Flags: []),
  5955. (Name: ParamCommonTasks; Flags: []),
  5956. (Name: ParamCommonLanguages; Flags: []),
  5957. (Name: ParamCommonCheck; Flags: []),
  5958. (Name: ParamCommonBeforeInstall; Flags: []),
  5959. (Name: ParamCommonAfterInstall; Flags: []),
  5960. (Name: ParamCommonMinVersion; Flags: []),
  5961. (Name: ParamCommonOnlyBelowVersion; Flags: []));
  5962. Flags: array[0..18] of PChar = (
  5963. 'nowait', 'waituntilidle', 'shellexec', 'skipifdoesntexist',
  5964. 'runminimized', 'runmaximized', 'showcheckbox', 'postinstall',
  5965. 'unchecked', 'skipifsilent', 'skipifnotsilent', 'hidewizard',
  5966. 'runhidden', 'waituntilterminated', '32bit', '64bit', 'runasoriginaluser',
  5967. 'runascurrentuser', 'dontlogparameters');
  5968. var
  5969. Values: array[TParam] of TParamValue;
  5970. NewRunEntry: PSetupRunEntry;
  5971. WaitFlagSpecified, RunAsOriginalUser, RunAsCurrentUser: Boolean;
  5972. begin
  5973. ExtractParameters(Line, ParamInfo, Values);
  5974. NewRunEntry := AllocMem(SizeOf(TSetupRunEntry));
  5975. try
  5976. with NewRunEntry^ do begin
  5977. MinVersion := SetupHeader.MinVersion;
  5978. ShowCmd := SW_SHOWNORMAL;
  5979. WaitFlagSpecified := False;
  5980. RunAsOriginalUser := False;
  5981. RunAsCurrentUser := False;
  5982. { Flags }
  5983. while True do
  5984. case ExtractFlag(Values[paFlags].Data, Flags) of
  5985. -2: Break;
  5986. -1: AbortCompileParamError(SCompilerParamUnknownFlag2, ParamCommonFlags);
  5987. 0: begin
  5988. if WaitFlagSpecified then
  5989. AbortCompileOnLine(SCompilerRunMultipleWaitFlags);
  5990. Wait := rwNoWait;
  5991. WaitFlagSpecified := True;
  5992. end;
  5993. 1: begin
  5994. if WaitFlagSpecified then
  5995. AbortCompileOnLine(SCompilerRunMultipleWaitFlags);
  5996. Wait := rwWaitUntilIdle;
  5997. WaitFlagSpecified := True;
  5998. end;
  5999. 2: Include(Options, roShellExec);
  6000. 3: Include(Options, roSkipIfDoesntExist);
  6001. 4: ShowCmd := SW_SHOWMINNOACTIVE;
  6002. 5: ShowCmd := SW_SHOWMAXIMIZED;
  6003. 6: begin
  6004. if (Ext = 1) then
  6005. AbortCompileParamError(SCompilerParamUnsupportedFlag, ParamCommonFlags);
  6006. WarningsList.Add(Format(SCompilerRunFlagObsolete, ['showcheckbox', 'postinstall']));
  6007. Include(Options, roPostInstall);
  6008. end;
  6009. 7: begin
  6010. if (Ext = 1) then
  6011. AbortCompileParamError(SCompilerParamUnsupportedFlag, ParamCommonFlags);
  6012. Include(Options, roPostInstall);
  6013. end;
  6014. 8: begin
  6015. if (Ext = 1) then
  6016. AbortCompileParamError(SCompilerParamUnsupportedFlag, ParamCommonFlags);
  6017. Include(Options, roUnchecked);
  6018. end;
  6019. 9: begin
  6020. if (Ext = 1) then
  6021. AbortCompileParamError(SCompilerParamUnsupportedFlag, ParamCommonFlags);
  6022. Include(Options, roSkipIfSilent);
  6023. end;
  6024. 10: begin
  6025. if (Ext = 1) then
  6026. AbortCompileParamError(SCompilerParamUnsupportedFlag, ParamCommonFlags);
  6027. Include(Options, roSkipIfNotSilent);
  6028. end;
  6029. 11: Include(Options, roHideWizard);
  6030. 12: ShowCmd := SW_HIDE;
  6031. 13: begin
  6032. if WaitFlagSpecified then
  6033. AbortCompileOnLine(SCompilerRunMultipleWaitFlags);
  6034. Wait := rwWaitUntilTerminated;
  6035. WaitFlagSpecified := True;
  6036. end;
  6037. 14: Include(Options, roRun32Bit);
  6038. 15: Include(Options, roRun64Bit);
  6039. 16: begin
  6040. if (Ext = 1) then
  6041. AbortCompileParamError(SCompilerParamUnsupportedFlag, ParamCommonFlags);
  6042. RunAsOriginalUser := True;
  6043. end;
  6044. 17: RunAsCurrentUser := True;
  6045. 18: Include(Options, roDontLogParameters);
  6046. end;
  6047. if not WaitFlagSpecified then begin
  6048. if roShellExec in Options then
  6049. Wait := rwNoWait
  6050. else
  6051. Wait := rwWaitUntilTerminated;
  6052. end;
  6053. if RunAsOriginalUser and RunAsCurrentUser then
  6054. AbortCompileOnLineFmt(SCompilerParamErrorBadCombo2,
  6055. [ParamCommonFlags, 'runasoriginaluser', 'runascurrentuser']);
  6056. if RunAsOriginalUser or
  6057. (not RunAsCurrentUser and (roPostInstall in Options)) then
  6058. Include(Options, roRunAsOriginalUser);
  6059. { Filename }
  6060. Name := Values[paFilename].Data;
  6061. { Parameters }
  6062. Parameters := Values[paParameters].Data;
  6063. { WorkingDir }
  6064. WorkingDir := Values[paWorkingDir].Data;
  6065. { RunOnceId }
  6066. if Values[paRunOnceId].Data <> '' then begin
  6067. if Ext = 0 then
  6068. AbortCompileOnLine(SCompilerRunCantUseRunOnceId);
  6069. end else if Ext = 1 then
  6070. MissingRunOnceIds := True;
  6071. RunOnceId := Values[paRunOnceId].Data;
  6072. { Description }
  6073. if (Ext = 1) and (Values[paDescription].Data <> '') then
  6074. AbortCompileOnLine(SCompilerUninstallRunCantUseDescription);
  6075. Description := Values[paDescription].Data;
  6076. { StatusMsg }
  6077. StatusMsg := Values[paStatusMsg].Data;
  6078. { Verb }
  6079. if not (roShellExec in Options) and Values[paVerb].Found then
  6080. AbortCompileOnLineFmt(SCompilerParamFlagMissing2,
  6081. ['shellexec', 'Verb']);
  6082. Verb := Values[paVerb].Data;
  6083. { Common parameters }
  6084. ProcessExpressionParameter(ParamCommonComponents, Values[paComponents].Data, EvalComponentIdentifier, True, Components);
  6085. ProcessExpressionParameter(ParamCommonTasks, Values[paTasks].Data, EvalTaskIdentifier, True, Tasks);
  6086. ProcessExpressionParameter(ParamCommonLanguages, Values[paLanguages].Data, EvalLanguageIdentifier, False, Languages);
  6087. Check := Values[paCheck].Data;
  6088. BeforeInstall := Values[paBeforeInstall].Data;
  6089. AfterInstall := Values[paAfterInstall].Data;
  6090. ProcessMinVersionParameter(Values[paMinVersion], MinVersion);
  6091. ProcessOnlyBelowVersionParameter(Values[paOnlyBelowVersion], OnlyBelowVersion);
  6092. if (roRun32Bit in Options) and (roRun64Bit in Options) then
  6093. AbortCompileOnLineFmt(SCompilerParamErrorBadCombo2,
  6094. [ParamCommonFlags, '32bit', '64bit']);
  6095. if (roRun32Bit in Options) and (roShellExec in Options) then
  6096. AbortCompileOnLineFmt(SCompilerParamErrorBadCombo2,
  6097. [ParamCommonFlags, '32bit', 'shellexec']);
  6098. if (roRun64Bit in Options) and (roShellExec in Options) then
  6099. AbortCompileOnLineFmt(SCompilerParamErrorBadCombo2,
  6100. [ParamCommonFlags, '64bit', 'shellexec']);
  6101. CheckCheckOrInstall(ParamCommonCheck, Check, cikCheck);
  6102. CheckCheckOrInstall(ParamCommonBeforeInstall, BeforeInstall, cikInstall);
  6103. CheckCheckOrInstall(ParamCommonAfterInstall, AfterInstall, cikInstall);
  6104. CheckConst(Name, MinVersion, []);
  6105. CheckConst(Parameters, MinVersion, []);
  6106. CheckConst(WorkingDir, MinVersion, []);
  6107. CheckConst(RunOnceId, MinVersion, []);
  6108. CheckConst(Description, MinVersion, []);
  6109. CheckConst(StatusMsg, MinVersion, []);
  6110. CheckConst(Verb, MinVersion, []);
  6111. end;
  6112. except
  6113. SEFreeRec(NewRunEntry, SetupRunEntryStrings, SetupRunEntryAnsiStrings);
  6114. raise;
  6115. end;
  6116. if Ext = 0 then begin
  6117. WriteDebugEntry(deRun, RunEntries.Count);
  6118. RunEntries.Add(NewRunEntry)
  6119. end
  6120. else begin
  6121. WriteDebugEntry(deUninstallRun, UninstallRunEntries.Count);
  6122. UninstallRunEntries.Add(NewRunEntry);
  6123. end;
  6124. end;
  6125. type
  6126. TLanguagesParam = (paName, paMessagesFile, paLicenseFile, paInfoBeforeFile, paInfoAfterFile);
  6127. const
  6128. ParamLanguagesName = 'Name';
  6129. ParamLanguagesMessagesFile = 'MessagesFile';
  6130. ParamLanguagesLicenseFile = 'LicenseFile';
  6131. ParamLanguagesInfoBeforeFile = 'InfoBeforeFile';
  6132. ParamLanguagesInfoAfterFile = 'InfoAfterFile';
  6133. LanguagesParamInfo: array[TLanguagesParam] of TParamInfo = (
  6134. (Name: ParamLanguagesName; Flags: [piRequired, piNoEmpty]),
  6135. (Name: ParamLanguagesMessagesFile; Flags: [piRequired, piNoEmpty]),
  6136. (Name: ParamLanguagesLicenseFile; Flags: [piNoEmpty]),
  6137. (Name: ParamLanguagesInfoBeforeFile; Flags: [piNoEmpty]),
  6138. (Name: ParamLanguagesInfoAfterFile; Flags: [piNoEmpty]));
  6139. procedure TSetupCompiler.EnumLanguagesPreProc(const Line: PChar; const Ext: Integer);
  6140. var
  6141. Values: array[TLanguagesParam] of TParamValue;
  6142. NewPreLangData: TPreLangData;
  6143. Filename: String;
  6144. begin
  6145. ExtractParameters(Line, LanguagesParamInfo, Values);
  6146. PreLangDataList.Expand;
  6147. NewPreLangData := nil;
  6148. try
  6149. NewPreLangData := TPreLangData.Create;
  6150. Filename := '';
  6151. InitPreLangData(NewPreLangData);
  6152. { Name }
  6153. if not IsValidIdentString(Values[paName].Data, False, False) then
  6154. AbortCompileOnLine(SCompilerLanguagesBadName);
  6155. NewPreLangData.Name := Values[paName].Data;
  6156. { MessagesFile }
  6157. Filename := Values[paMessagesFile].Data;
  6158. except
  6159. NewPreLangData.Free;
  6160. raise;
  6161. end;
  6162. PreLangDataList.Add(NewPreLangData);
  6163. ReadMessagesFromFilesPre(Filename, PreLangDataList.Count-1);
  6164. end;
  6165. procedure TSetupCompiler.EnumLanguagesProc(const Line: PChar; const Ext: Integer);
  6166. var
  6167. Values: array[TLanguagesParam] of TParamValue;
  6168. NewLanguageEntry: PSetupLanguageEntry;
  6169. NewLangData: TLangData;
  6170. Filename: String;
  6171. begin
  6172. ExtractParameters(Line, LanguagesParamInfo, Values);
  6173. LanguageEntries.Expand;
  6174. LangDataList.Expand;
  6175. NewLangData := nil;
  6176. NewLanguageEntry := AllocMem(SizeOf(TSetupLanguageEntry));
  6177. try
  6178. NewLangData := TLangData.Create;
  6179. Filename := '';
  6180. InitLanguageEntry(NewLanguageEntry^);
  6181. { Name }
  6182. if not IsValidIdentString(Values[paName].Data, False, False) then
  6183. AbortCompileOnLine(SCompilerLanguagesBadName);
  6184. NewLanguageEntry.Name := Values[paName].Data;
  6185. { MessagesFile }
  6186. Filename := Values[paMessagesFile].Data;
  6187. { LicenseFile }
  6188. if (Values[paLicenseFile].Data <> '') then begin
  6189. AddStatus(Format(SCompilerStatusReadingInFile, [Values[paLicenseFile].Data]));
  6190. ReadTextFile(PrependSourceDirName(Values[paLicenseFile].Data), LanguageEntries.Count,
  6191. NewLanguageEntry.LicenseText);
  6192. end;
  6193. { InfoBeforeFile }
  6194. if (Values[paInfoBeforeFile].Data <> '') then begin
  6195. AddStatus(Format(SCompilerStatusReadingInFile, [Values[paInfoBeforeFile].Data]));
  6196. ReadTextFile(PrependSourceDirName(Values[paInfoBeforeFile].Data), LanguageEntries.Count,
  6197. NewLanguageEntry.InfoBeforeText);
  6198. end;
  6199. { InfoAfterFile }
  6200. if (Values[paInfoAfterFile].Data <> '') then begin
  6201. AddStatus(Format(SCompilerStatusReadingInFile, [Values[paInfoAfterFile].Data]));
  6202. ReadTextFile(PrependSourceDirName(Values[paInfoAfterFile].Data), LanguageEntries.Count,
  6203. NewLanguageEntry.InfoAfterText);
  6204. end;
  6205. except
  6206. NewLangData.Free;
  6207. SEFreeRec(NewLanguageEntry, SetupLanguageEntryStrings, SetupLanguageEntryAnsiStrings);
  6208. raise;
  6209. end;
  6210. LanguageEntries.Add(NewLanguageEntry);
  6211. LangDataList.Add(NewLangData);
  6212. ReadMessagesFromFiles(Filename, LanguageEntries.Count-1);
  6213. end;
  6214. procedure TSetupCompiler.EnumMessagesProc(const Line: PChar; const Ext: Integer);
  6215. var
  6216. P, P2: PChar;
  6217. I, ID, LangIndex: Integer;
  6218. N, M: String;
  6219. begin
  6220. P := StrScan(Line, '=');
  6221. if P = nil then
  6222. AbortCompileOnLine(SCompilerMessagesMissingEquals);
  6223. SetString(N, Line, P - Line);
  6224. N := Trim(N);
  6225. LangIndex := ExtractLangIndex(Self, N, Ext, False);
  6226. ID := GetEnumValue(TypeInfo(TSetupMessageID), 'msg' + N);
  6227. if ID = -1 then begin
  6228. if LangIndex = -2 then
  6229. AbortCompileOnLineFmt(SCompilerMessagesNotRecognizedDefault, [N])
  6230. else begin
  6231. if NotRecognizedMessagesWarning then begin
  6232. if LineFilename = '' then
  6233. WarningsList.Add(Format(SCompilerMessagesNotRecognizedWarning, [N]))
  6234. else
  6235. WarningsList.Add(Format(SCompilerMessagesNotRecognizedInFileWarning,
  6236. [N, LineFilename]));
  6237. end;
  6238. Exit;
  6239. end;
  6240. end;
  6241. Inc(P);
  6242. M := P;
  6243. { Replace %n with actual CR/LF characters }
  6244. P2 := PChar(M);
  6245. while True do begin
  6246. P2 := StrPos(P2, '%n');
  6247. if P2 = nil then Break;
  6248. P2[0] := #13;
  6249. P2[1] := #10;
  6250. Inc(P2, 2);
  6251. end;
  6252. if LangIndex = -2 then begin
  6253. { Special -2 value means store in DefaultLangData }
  6254. DefaultLangData.Messages[TSetupMessageID(ID)] := M;
  6255. DefaultLangData.MessagesDefined[TSetupMessageID(ID)] := True;
  6256. end
  6257. else begin
  6258. for I := 0 to LangDataList.Count-1 do begin
  6259. if (LangIndex <> -1) and (I <> LangIndex) then
  6260. Continue;
  6261. TLangData(LangDataList[I]).Messages[TSetupMessageID(ID)] := M;
  6262. TLangData(LangDataList[I]).MessagesDefined[TSetupMessageID(ID)] := True;
  6263. end;
  6264. end;
  6265. end;
  6266. procedure TSetupCompiler.EnumCustomMessagesProc(const Line: PChar; const Ext: Integer);
  6267. function ExpandNewlines(const S: String): String;
  6268. { Replaces '%n' with #13#10 }
  6269. var
  6270. L, I: Integer;
  6271. begin
  6272. Result := S;
  6273. L := Length(Result);
  6274. I := 1;
  6275. while I < L do begin
  6276. if Result[I] = '%' then begin
  6277. if Result[I+1] = 'n' then begin
  6278. Result[I] := #13;
  6279. Result[I+1] := #10;
  6280. end;
  6281. Inc(I);
  6282. end;
  6283. Inc(I);
  6284. end;
  6285. end;
  6286. var
  6287. P: PChar;
  6288. LangIndex: Integer;
  6289. N: String;
  6290. I: Integer;
  6291. ExistingCustomMessageEntry, NewCustomMessageEntry: PSetupCustomMessageEntry;
  6292. begin
  6293. P := StrScan(Line, '=');
  6294. if P = nil then
  6295. AbortCompileOnLine(SCompilerMessagesMissingEquals);
  6296. SetString(N, Line, P - Line);
  6297. N := Trim(N);
  6298. LangIndex := ExtractLangIndex(Self, N, Ext, False);
  6299. Inc(P);
  6300. CustomMessageEntries.Expand;
  6301. NewCustomMessageEntry := AllocMem(SizeOf(TSetupCustomMessageEntry));
  6302. try
  6303. if not IsValidIdentString(N, False, True) then
  6304. AbortCompileOnLine(SCompilerCustomMessageBadName);
  6305. { Delete existing entries}
  6306. for I := CustomMessageEntries.Count-1 downto 0 do begin
  6307. ExistingCustomMessageEntry := CustomMessageEntries[I];
  6308. if (CompareText(ExistingCustomMessageEntry.Name, N) = 0) and
  6309. ((LangIndex = -1) or (ExistingCustomMessageEntry.LangIndex = LangIndex)) then begin
  6310. SEFreeRec(ExistingCustomMessageEntry, SetupCustomMessageEntryStrings,
  6311. SetupCustomMessageEntryAnsiStrings);
  6312. CustomMessageEntries.Delete(I);
  6313. end;
  6314. end;
  6315. { Setup the new one }
  6316. NewCustomMessageEntry.Name := N;
  6317. NewCustomMessageEntry.Value := ExpandNewlines(P);
  6318. NewCustomMessageEntry.LangIndex := LangIndex;
  6319. except
  6320. SEFreeRec(NewCustomMessageEntry, SetupCustomMessageEntryStrings, SetupCustomMessageEntryAnsiStrings);
  6321. raise;
  6322. end;
  6323. CustomMessageEntries.Add(NewCustomMessageEntry);
  6324. end;
  6325. procedure TSetupCompiler.CheckCustomMessageDefinitions;
  6326. { Checks 'language completeness' of custom message constants }
  6327. var
  6328. MissingLang, Found: Boolean;
  6329. I, J, K: Integer;
  6330. CustomMessage1, CustomMessage2: PSetupCustomMessageEntry;
  6331. begin
  6332. for I := 0 to CustomMessageEntries.Count-1 do begin
  6333. CustomMessage1 := PSetupCustomMessageEntry(CustomMessageEntries[I]);
  6334. if CustomMessage1.LangIndex <> -1 then begin
  6335. MissingLang := False;
  6336. for J := 0 to LanguageEntries.Count-1 do begin
  6337. { Check whether the outer custom message name exists for this language }
  6338. Found := False;
  6339. for K := 0 to CustomMessageEntries.Count-1 do begin
  6340. CustomMessage2 := PSetupCustomMessageEntry(CustomMessageEntries[K]);
  6341. if CompareText(CustomMessage1.Name, CustomMessage2.Name) = 0 then begin
  6342. if (CustomMessage2.LangIndex = -1) or (CustomMessage2.LangIndex = J) then begin
  6343. Found := True;
  6344. Break;
  6345. end;
  6346. end;
  6347. end;
  6348. if not Found then begin
  6349. WarningsList.Add(Format(SCompilerCustomMessagesMissingLangWarning,
  6350. [CustomMessage1.Name, PSetupLanguageEntry(LanguageEntries[J]).Name,
  6351. PSetupLanguageEntry(LanguageEntries[CustomMessage1.LangIndex]).Name]));
  6352. MissingLang := True;
  6353. end;
  6354. end;
  6355. if MissingLang then begin
  6356. { The custom message CustomMessage1.Name is not 'language complete'.
  6357. Force it to be by setting CustomMessage1.LangIndex to -1. This will
  6358. cause languages that do not define the custom message to use this
  6359. one (i.e. the first definition of it). Note: Languages that do define
  6360. the custom message in subsequent entries will override this entry,
  6361. since Setup looks for the *last* matching entry. }
  6362. CustomMessage1.LangIndex := -1;
  6363. end;
  6364. end;
  6365. end;
  6366. end;
  6367. procedure TSetupCompiler.CheckCustomMessageReferences;
  6368. { Checks existence of expected custom message constants }
  6369. var
  6370. LineInfo: TLineInfo;
  6371. Found: Boolean;
  6372. S: String;
  6373. I, J: Integer;
  6374. begin
  6375. for I := 0 to ExpectedCustomMessageNames.Count-1 do begin
  6376. Found := False;
  6377. S := ExpectedCustomMessageNames[I];
  6378. for J := 0 to CustomMessageEntries.Count-1 do begin
  6379. if CompareText(PSetupCustomMessageEntry(CustomMessageEntries[J]).Name, S) = 0 then begin
  6380. Found := True;
  6381. Break;
  6382. end;
  6383. end;
  6384. if not Found then begin
  6385. LineInfo := TLineInfo(ExpectedCustomMessageNames.Objects[I]);
  6386. LineFilename := LineInfo.Filename;
  6387. LineNumber := LineInfo.FileLineNumber;
  6388. AbortCompileFmt(SCompilerCustomMessagesMissingName, [S]);
  6389. end;
  6390. end;
  6391. end;
  6392. procedure TSetupCompiler.InitPreLangData(const APreLangData: TPreLangData);
  6393. { Initializes a TPreLangData object with the default settings }
  6394. begin
  6395. with APreLangData do begin
  6396. Name := 'default';
  6397. LanguageCodePage := 0;
  6398. end;
  6399. end;
  6400. procedure TSetupCompiler.InitLanguageEntry(var ALanguageEntry: TSetupLanguageEntry);
  6401. { Initializes a TSetupLanguageEntry record with the default settings }
  6402. begin
  6403. with ALanguageEntry do begin
  6404. Name := 'default';
  6405. LanguageName := 'English';
  6406. LanguageID := $0409; { U.S. English }
  6407. DialogFontName := DefaultDialogFontName;
  6408. DialogFontSize := 8;
  6409. TitleFontName := 'Arial';
  6410. TitleFontSize := 29;
  6411. WelcomeFontName := 'Verdana';
  6412. WelcomeFontSize := 12;
  6413. CopyrightFontName := 'Arial';
  6414. CopyrightFontSize := 8;
  6415. LicenseText := '';
  6416. InfoBeforeText := '';
  6417. InfoAfterText := '';
  6418. end;
  6419. end;
  6420. procedure TSetupCompiler.ReadMessagesFromFilesPre(const AFiles: String;
  6421. const ALangIndex: Integer);
  6422. var
  6423. S, Filename: String;
  6424. begin
  6425. S := AFiles;
  6426. while True do begin
  6427. Filename := ExtractStr(S, ',');
  6428. if Filename = '' then
  6429. Break;
  6430. Filename := PathExpand(PrependSourceDirName(Filename));
  6431. AddStatus(Format(SCompilerStatusReadingInFile, [Filename]));
  6432. EnumIniSection(EnumLangOptionsPreProc, 'LangOptions', ALangIndex, False, True, Filename, True, True);
  6433. CallIdleProc;
  6434. end;
  6435. end;
  6436. procedure TSetupCompiler.ReadMessagesFromFiles(const AFiles: String;
  6437. const ALangIndex: Integer);
  6438. var
  6439. S, Filename: String;
  6440. begin
  6441. S := AFiles;
  6442. while True do begin
  6443. Filename := ExtractStr(S, ',');
  6444. if Filename = '' then
  6445. Break;
  6446. Filename := PathExpand(PrependSourceDirName(Filename));
  6447. AddStatus(Format(SCompilerStatusReadingInFile, [Filename]));
  6448. EnumIniSection(EnumLangOptionsProc, 'LangOptions', ALangIndex, False, True, Filename, True, False);
  6449. CallIdleProc;
  6450. EnumIniSection(EnumMessagesProc, 'Messages', ALangIndex, False, True, Filename, True, False);
  6451. CallIdleProc;
  6452. EnumIniSection(EnumCustomMessagesProc, 'CustomMessages', ALangIndex, False, True, Filename, True, False);
  6453. CallIdleProc;
  6454. end;
  6455. end;
  6456. procedure TSetupCompiler.ReadDefaultMessages;
  6457. var
  6458. J: TSetupMessageID;
  6459. begin
  6460. { Read messages from Default.isl into DefaultLangData }
  6461. EnumIniSection(EnumMessagesProc, 'Messages', -2, False, True, 'compiler:Default.isl', True, False);
  6462. CallIdleProc;
  6463. { Check for missing messages in Default.isl }
  6464. for J := Low(DefaultLangData.Messages) to High(DefaultLangData.Messages) do
  6465. if not DefaultLangData.MessagesDefined[J] then
  6466. AbortCompileFmt(SCompilerMessagesMissingDefaultMessage,
  6467. [Copy(GetEnumName(TypeInfo(TSetupMessageID), Ord(J)), 4, Maxint)]);
  6468. { ^ Copy(..., 4, Maxint) is to skip past "msg" }
  6469. end;
  6470. procedure TSetupCompiler.ReadMessagesFromScriptPre;
  6471. procedure CreateDefaultLanguageEntryPre;
  6472. var
  6473. NewPreLangData: TPreLangData;
  6474. begin
  6475. PreLangDataList.Expand;
  6476. NewPreLangData := nil;
  6477. try
  6478. NewPreLangData := TPreLangData.Create;
  6479. InitPreLangData(NewPreLangData);
  6480. except
  6481. NewPreLangData.Free;
  6482. raise;
  6483. end;
  6484. PreLangDataList.Add(NewPreLangData);
  6485. ReadMessagesFromFilesPre('compiler:Default.isl', PreLangDataList.Count-1);
  6486. end;
  6487. begin
  6488. { If there were no [Languages] entries, take this opportunity to create a
  6489. default language }
  6490. if PreLangDataList.Count = 0 then begin
  6491. CreateDefaultLanguageEntryPre;
  6492. CallIdleProc;
  6493. end;
  6494. { Then read the [LangOptions] section in the script }
  6495. AddStatus(SCompilerStatusReadingInScriptMsgs);
  6496. EnumIniSection(EnumLangOptionsPreProc, 'LangOptions', -1, False, True, '', True, False);
  6497. CallIdleProc;
  6498. end;
  6499. procedure TSetupCompiler.ReadMessagesFromScript;
  6500. procedure CreateDefaultLanguageEntry;
  6501. var
  6502. NewLanguageEntry: PSetupLanguageEntry;
  6503. NewLangData: TLangData;
  6504. begin
  6505. LanguageEntries.Expand;
  6506. LangDataList.Expand;
  6507. NewLangData := nil;
  6508. NewLanguageEntry := AllocMem(SizeOf(TSetupLanguageEntry));
  6509. try
  6510. NewLangData := TLangData.Create;
  6511. InitLanguageEntry(NewLanguageEntry^);
  6512. except
  6513. NewLangData.Free;
  6514. SEFreeRec(NewLanguageEntry, SetupLanguageEntryStrings, SetupLanguageEntryAnsiStrings);
  6515. raise;
  6516. end;
  6517. LanguageEntries.Add(NewLanguageEntry);
  6518. LangDataList.Add(NewLangData);
  6519. ReadMessagesFromFiles('compiler:Default.isl', LanguageEntries.Count-1);
  6520. end;
  6521. function IsOptional(const MessageID: TSetupMessageID): Boolean;
  6522. begin
  6523. Result := False; { Currently there are no optional messages }
  6524. end;
  6525. var
  6526. I: Integer;
  6527. LangData: TLangData;
  6528. J: TSetupMessageID;
  6529. begin
  6530. { If there were no [Languages] entries, take this opportunity to create a
  6531. default language }
  6532. if LanguageEntries.Count = 0 then begin
  6533. CreateDefaultLanguageEntry;
  6534. CallIdleProc;
  6535. end;
  6536. { Then read the [LangOptions] & [Messages] & [CustomMessages] sections in the script }
  6537. AddStatus(SCompilerStatusReadingInScriptMsgs);
  6538. EnumIniSection(EnumLangOptionsProc, 'LangOptions', -1, False, True, '', True, False);
  6539. CallIdleProc;
  6540. EnumIniSection(EnumMessagesProc, 'Messages', -1, False, True, '', True, False);
  6541. CallIdleProc;
  6542. EnumIniSection(EnumCustomMessagesProc, 'CustomMessages', -1, False, True, '', True, False);
  6543. CallIdleProc;
  6544. { Check for missing messages }
  6545. for I := 0 to LanguageEntries.Count-1 do begin
  6546. LangData := LangDataList[I];
  6547. for J := Low(LangData.Messages) to High(LangData.Messages) do
  6548. if not LangData.MessagesDefined[J] and not IsOptional(J) then begin
  6549. { Use the message from Default.isl }
  6550. if MissingMessagesWarning and not (J in [msgHelpTextNote, msgTranslatorNote]) then
  6551. WarningsList.Add(Format(SCompilerMessagesMissingMessageWarning,
  6552. [Copy(GetEnumName(TypeInfo(TSetupMessageID), Ord(J)), 4, Maxint),
  6553. PSetupLanguageEntry(LanguageEntries[I]).Name]));
  6554. { ^ Copy(..., 4, Maxint) is to skip past "msg" }
  6555. LangData.Messages[J] := DefaultLangData.Messages[J];
  6556. end;
  6557. end;
  6558. CallIdleProc;
  6559. end;
  6560. procedure TSetupCompiler.PopulateLanguageEntryData;
  6561. { Fills in each language entry's Data field, based on the messages in
  6562. LangDataList }
  6563. type
  6564. PMessagesDataStructure = ^TMessagesDataStructure;
  6565. TMessagesDataStructure = packed record
  6566. ID: TMessagesHdrID;
  6567. Header: TMessagesHeader;
  6568. MsgData: array[0..0] of Byte;
  6569. end;
  6570. var
  6571. L: Integer;
  6572. LangData: TLangData;
  6573. M: TMemoryStream;
  6574. I: TSetupMessageID;
  6575. Header: TMessagesHeader;
  6576. begin
  6577. for L := 0 to LanguageEntries.Count-1 do begin
  6578. LangData := LangDataList[L];
  6579. M := TMemoryStream.Create;
  6580. try
  6581. M.WriteBuffer(MessagesHdrID, SizeOf(MessagesHdrID));
  6582. FillChar(Header, SizeOf(Header), 0);
  6583. M.WriteBuffer(Header, SizeOf(Header)); { overwritten later }
  6584. for I := Low(LangData.Messages) to High(LangData.Messages) do
  6585. M.WriteBuffer(PChar(LangData.Messages[I])^, (Length(LangData.Messages[I]) + 1) * SizeOf(LangData.Messages[I][1]));
  6586. Header.NumMessages := Ord(High(LangData.Messages)) - Ord(Low(LangData.Messages)) + 1;
  6587. Header.TotalSize := M.Size;
  6588. Header.NotTotalSize := not Header.TotalSize;
  6589. Header.CRCMessages := GetCRC32(PMessagesDataStructure(M.Memory).MsgData,
  6590. M.Size - (SizeOf(MessagesHdrID) + SizeOf(Header)));
  6591. PMessagesDataStructure(M.Memory).Header := Header;
  6592. SetString(PSetupLanguageEntry(LanguageEntries[L]).Data, PAnsiChar(M.Memory),
  6593. M.Size);
  6594. finally
  6595. M.Free;
  6596. end;
  6597. end;
  6598. end;
  6599. procedure TSetupCompiler.EnumCodeProc(const Line: PChar; const Ext: Integer);
  6600. var
  6601. CodeTextLineInfo: TLineInfo;
  6602. begin
  6603. CodeTextLineInfo := TLineInfo.Create;
  6604. CodeTextLineInfo.Filename := LineFilename;
  6605. CodeTextLineInfo.FileLineNumber := LineNumber;
  6606. CodeText.AddObject(Line, CodeTextLineInfo);
  6607. end;
  6608. procedure TSetupCompiler.ReadCode;
  6609. begin
  6610. { Read [Code] section }
  6611. AddStatus(SCompilerStatusReadingCode);
  6612. EnumIniSection(EnumCodeProc, 'Code', 0, False, False, '', False, False);
  6613. CallIdleProc;
  6614. end;
  6615. procedure TSetupCompiler.CodeCompilerOnLineToLineInfo(const Line: LongInt; var Filename: String; var FileLine: LongInt);
  6616. var
  6617. CodeTextLineInfo: TLineInfo;
  6618. begin
  6619. if (Line > 0) and (Line <= CodeText.Count) then begin
  6620. CodeTextLineInfo := TLineInfo(CodeText.Objects[Line-1]);
  6621. Filename := CodeTextLineInfo.Filename;
  6622. FileLine := CodeTextLineInfo.FileLineNumber;
  6623. end;
  6624. end;
  6625. procedure TSetupCompiler.CodeCompilerOnUsedLine(const Filename: String; const Line, Position: LongInt; const IsProcExit: Boolean);
  6626. var
  6627. OldLineFilename: String;
  6628. OldLineNumber: Integer;
  6629. begin
  6630. OldLineFilename := LineFilename;
  6631. OldLineNumber := LineNumber;
  6632. try
  6633. LineFilename := Filename;
  6634. LineNumber := Line;
  6635. WriteDebugEntry(deCodeLine, Position, IsProcExit);
  6636. finally
  6637. LineFilename := OldLineFilename;
  6638. LineNumber := OldLineNumber;
  6639. end;
  6640. end;
  6641. procedure TSetupCompiler.CodeCompilerOnUsedVariable(const Filename: String; const Line, Col, Param1, Param2, Param3: LongInt; const Param4: AnsiString);
  6642. var
  6643. Rec: TVariableDebugEntry;
  6644. begin
  6645. if Length(Param4)+1 <= SizeOf(Rec.Param4) then begin
  6646. Rec.FileIndex := FilenameToFileIndex(Filename);
  6647. Rec.LineNumber := Line;
  6648. Rec.Col := Col;
  6649. Rec.Param1 := Param1;
  6650. Rec.Param2 := Param2;
  6651. Rec.Param3 := Param3;
  6652. FillChar(Rec.Param4, SizeOf(Rec.Param4), 0);
  6653. AnsiStrings.StrPCopy(Rec.Param4, Param4);
  6654. CodeDebugInfo.WriteBuffer(Rec, SizeOf(Rec));
  6655. Inc(VariableDebugEntryCount);
  6656. end;
  6657. end;
  6658. procedure TSetupCompiler.CodeCompilerOnError(const Msg: String; const ErrorFilename: String; const ErrorLine: LongInt);
  6659. begin
  6660. LineFilename := ErrorFilename;
  6661. LineNumber := ErrorLine;
  6662. AbortCompile(Msg);
  6663. end;
  6664. procedure TSetupCompiler.CodeCompilerOnWarning(const Msg: String);
  6665. begin
  6666. WarningsList.Add(Msg);
  6667. end;
  6668. procedure TSetupCompiler.CompileCode;
  6669. var
  6670. CodeStr: String;
  6671. CompiledCodeDebugInfo: AnsiString;
  6672. begin
  6673. { Compile CodeText }
  6674. if (CodeText.Count > 0) or (CodeCompiler.ExportCount > 0) then begin
  6675. if CodeText.Count > 0 then
  6676. AddStatus(SCompilerStatusCompilingCode);
  6677. //don't forget highlighter!
  6678. //setup
  6679. CodeCompiler.AddExport('InitializeSetup', 'Boolean', True, False, '', 0);
  6680. CodeCompiler.AddExport('DeinitializeSetup', '0', True, False, '', 0);
  6681. CodeCompiler.AddExport('CurStepChanged', '0 @TSetupStep', True, False, '', 0);
  6682. CodeCompiler.AddExport('NextButtonClick', 'Boolean @LongInt', True, False, '', 0);
  6683. CodeCompiler.AddExport('BackButtonClick', 'Boolean @LongInt', True, False, '', 0);
  6684. CodeCompiler.AddExport('CancelButtonClick', '0 @LongInt !Boolean !Boolean', True, False, '', 0);
  6685. CodeCompiler.AddExport('ShouldSkipPage', 'Boolean @LongInt', True, False, '', 0);
  6686. CodeCompiler.AddExport('CurPageChanged', '0 @LongInt', True, False, '', 0);
  6687. CodeCompiler.AddExport('CheckPassword', 'Boolean @String', True, False, '', 0);
  6688. CodeCompiler.AddExport('NeedRestart', 'Boolean', True, False, '', 0);
  6689. CodeCompiler.AddExport('RegisterPreviousData', '0 @LongInt', True, False, '', 0);
  6690. CodeCompiler.AddExport('CheckSerial', 'Boolean @String', True, False, '', 0);
  6691. CodeCompiler.AddExport('InitializeWizard', '0', True, False, '', 0);
  6692. CodeCompiler.AddExport('RegisterExtraCloseApplicationsResources', '0', True, False, '', 0);
  6693. CodeCompiler.AddExport('CurInstallProgressChanged', '0 @LongInt @LongInt', True, False, '', 0);
  6694. CodeCompiler.AddExport('UpdateReadyMemo', 'String @String @String @String @String @String @String @String @String', True, False, '', 0);
  6695. CodeCompiler.AddExport('GetCustomSetupExitCode', 'LongInt', True, False, '', 0);
  6696. CodeCompiler.AddExport('PrepareToInstall', 'String !Boolean', True, False, '', 0);
  6697. //uninstall
  6698. CodeCompiler.AddExport('InitializeUninstall', 'Boolean', True, False, '', 0);
  6699. CodeCompiler.AddExport('DeinitializeUninstall', '0', True, False, '', 0);
  6700. CodeCompiler.AddExport('CurUninstallStepChanged', '0 @TUninstallStep', True, False, '', 0);
  6701. CodeCompiler.AddExport('UninstallNeedRestart', 'Boolean', True, False, '', 0);
  6702. CodeCompiler.AddExport('InitializeUninstallProgressForm', '0', True, False, '', 0);
  6703. CodeStr := CodeText.Text;
  6704. { Remove trailing CR-LF so that ROPS will never report an error on
  6705. line CodeText.Count, one past the last actual line }
  6706. if Length(CodeStr) >= Length(#13#10) then
  6707. SetLength(CodeStr, Length(CodeStr) - Length(#13#10));
  6708. CodeCompiler.Compile(CodeStr, CompiledCodeText, CompiledCodeDebugInfo);
  6709. if CodeCompiler.FunctionFound('SkipCurPage') then
  6710. AbortCompileFmt(SCompilerCodeUnsupportedEventFunction, ['SkipCurPage',
  6711. 'ShouldSkipPage']);
  6712. WriteCompiledCodeText(CompiledCodeText);
  6713. WriteCompiledCodeDebugInfo(CompiledCodeDebugInfo);
  6714. end else begin
  6715. CompiledCodeText := '';
  6716. { Check if there were references to [Code] functions despite there being
  6717. no [Code] section }
  6718. CodeCompiler.CheckExports();
  6719. end;
  6720. end;
  6721. procedure TSetupCompiler.AddSignTool(const Name, Command: String);
  6722. var
  6723. SignTool: TSignTool;
  6724. begin
  6725. SignToolList.Expand;
  6726. SignTool := TSignTool.Create();
  6727. SignTool.Name := Name;
  6728. SignTool.Command := Command;
  6729. SignToolList.Add(SignTool);
  6730. end;
  6731. procedure TSetupCompiler.Sign(AExeFilename: String);
  6732. var
  6733. I, SignToolIndex: Integer;
  6734. SignTool: TSignTool;
  6735. begin
  6736. for I := 0 to SignTools.Count - 1 do begin
  6737. SignToolIndex := FindSignToolIndexByName(SignTools[I]); //can't fail, already checked
  6738. SignTool := TSignTool(SignToolList[SignToolIndex]);
  6739. SignCommand(SignTool.Name, SignTool.Command, SignToolsParams[I], AExeFilename, SignToolRetryCount, SignToolRetryDelay, SignToolMinimumTimeBetween, SignToolRunMinimized);
  6740. end;
  6741. end;
  6742. procedure TSetupCompiler.SignCommand(const AName, ACommand, AParams, AExeFilename: String; const RetryCount, RetryDelay, MinimumTimeBetween: Integer; const RunMinimized: Boolean);
  6743. function FmtCommand(S: PChar; const AParams, AFileName: String; var AFileNameSequenceFound: Boolean): String;
  6744. var
  6745. P: PChar;
  6746. Z: String;
  6747. begin
  6748. Result := '';
  6749. AFileNameSequenceFound := False;
  6750. if S = nil then Exit;
  6751. while True do begin
  6752. P := StrScan(S, '$');
  6753. if P = nil then begin
  6754. Result := Result + S;
  6755. Break;
  6756. end;
  6757. if P <> S then begin
  6758. SetString(Z, S, P - S);
  6759. Result := Result + Z;
  6760. S := P;
  6761. end;
  6762. Inc(P);
  6763. if (P^ = 'p') then begin
  6764. Result := Result + AParams;
  6765. Inc(S, 2);
  6766. end
  6767. else if (P^ = 'f') then begin
  6768. Result := Result + '"' + AFileName + '"';
  6769. AFileNameSequenceFound := True;
  6770. Inc(S, 2);
  6771. end
  6772. else if (P^ = 'q') then begin
  6773. Result := Result + '"';
  6774. Inc(S, 2);
  6775. end
  6776. else begin
  6777. Result := Result + '$';
  6778. Inc(S);
  6779. if P^ = '$' then
  6780. Inc(S);
  6781. end;
  6782. end;
  6783. end;
  6784. procedure InternalSignCommand(const AFormattedCommand: String;
  6785. const Delay: Cardinal);
  6786. var
  6787. StartupInfo: TStartupInfo;
  6788. ProcessInfo: TProcessInformation;
  6789. LastError, ExitCode: DWORD;
  6790. begin
  6791. if Delay <> 0 then begin
  6792. AddStatus(Format(SCompilerStatusSigningWithDelay, [AName, Delay, AFormattedCommand]));
  6793. Sleep(Delay);
  6794. end else
  6795. AddStatus(Format(SCompilerStatusSigning, [AName, AFormattedCommand]));
  6796. LastSignCommandStartTick := GetTickCount;
  6797. FillChar(StartupInfo, SizeOf(StartupInfo), 0);
  6798. StartupInfo.cb := SizeOf(StartupInfo);
  6799. StartupInfo.dwFlags := STARTF_USESHOWWINDOW;
  6800. StartupInfo.wShowWindow := IfThen(RunMinimized, SW_SHOWMINNOACTIVE, SW_SHOW);
  6801. if not CreateProcess(nil, PChar(AFormattedCommand), nil, nil, False,
  6802. CREATE_DEFAULT_ERROR_MODE, nil, PChar(CompilerDir), StartupInfo, ProcessInfo) then begin
  6803. LastError := GetLastError;
  6804. AbortCompileFmt(SCompilerSignToolCreateProcessFailed, [LastError,
  6805. Win32ErrorString(LastError)]);
  6806. end;
  6807. CloseHandle(ProcessInfo.hThread);
  6808. try
  6809. while True do begin
  6810. case WaitForSingleObject(ProcessInfo.hProcess, 50) of
  6811. WAIT_OBJECT_0: Break;
  6812. WAIT_TIMEOUT: CallIdleProc;
  6813. else
  6814. AbortCompile('Sign: WaitForSingleObject failed');
  6815. end;
  6816. end;
  6817. if not GetExitCodeProcess(ProcessInfo.hProcess, ExitCode) then
  6818. AbortCompile('Sign: GetExitCodeProcess failed');
  6819. if ExitCode <> 0 then
  6820. AbortCompileFmt(SCompilerSignToolNonZeroExitCode, [ExitCode]);
  6821. finally
  6822. CloseHandle(ProcessInfo.hProcess);
  6823. end;
  6824. end;
  6825. var
  6826. Params, Command: String;
  6827. MinimumTimeBetweenDelay: Integer;
  6828. I: Integer;
  6829. FileNameSequenceFound1, FileNameSequenceFound2: Boolean;
  6830. begin
  6831. Params := FmtCommand(PChar(AParams), '', AExeFileName, FileNameSequenceFound1);
  6832. Command := FmtCommand(PChar(ACommand), Params, AExeFileName, FileNameSequenceFound2);
  6833. if not FileNameSequenceFound1 and not FileNameSequenceFound2 then
  6834. AbortCompileFmt(SCompilerSignToolFileNameSequenceNotFound, [AName]);
  6835. for I := 0 to RetryCount do begin
  6836. try
  6837. if (MinimumTimeBetween <> 0) and (LastSignCommandStartTick <> 0) then begin
  6838. MinimumTimeBetweenDelay := MinimumTimeBetween - Integer(GetTickCount - LastSignCommandStartTick);
  6839. if MinimumTimeBetweenDelay < 0 then
  6840. MinimumTimeBetweenDelay := 0;
  6841. end else
  6842. MinimumTimeBetweenDelay := 0;
  6843. InternalSignCommand(Command, MinimumTimeBetweenDelay);
  6844. Break;
  6845. except on E: Exception do
  6846. if I < RetryCount then begin
  6847. AddStatus(Format(SCompilerStatusWillRetrySigning, [E.Message, RetryCount-I]));
  6848. Sleep(RetryDelay);
  6849. end else
  6850. raise;
  6851. end;
  6852. end;
  6853. end;
  6854. procedure TSetupCompiler.Compile;
  6855. procedure InitDebugInfo;
  6856. var
  6857. Header: TDebugInfoHeader;
  6858. begin
  6859. DebugEntryCount := 0;
  6860. VariableDebugEntryCount := 0;
  6861. DebugInfo.Clear;
  6862. CodeDebugInfo.Clear;
  6863. Header.ID := DebugInfoHeaderID;
  6864. Header.Version := DebugInfoHeaderVersion;
  6865. Header.DebugEntryCount := 0;
  6866. Header.CompiledCodeTextLength := 0;
  6867. Header.CompiledCodeDebugInfoLength := 0;
  6868. DebugInfo.WriteBuffer(Header, SizeOf(Header));
  6869. end;
  6870. procedure FinalizeDebugInfo;
  6871. var
  6872. Header: TDebugInfoHeader;
  6873. begin
  6874. DebugInfo.CopyFrom(CodeDebugInfo, 0);
  6875. { Update the header }
  6876. DebugInfo.Seek(0, soFromBeginning);
  6877. DebugInfo.ReadBuffer(Header, SizeOf(Header));
  6878. Header.DebugEntryCount := DebugEntryCount;
  6879. Header.VariableDebugEntryCount := VariableDebugEntryCount;
  6880. Header.CompiledCodeTextLength := CompiledCodeTextLength;
  6881. Header.CompiledCodeDebugInfoLength := CompiledCodeDebugInfoLength;
  6882. DebugInfo.Seek(0, soFromBeginning);
  6883. DebugInfo.WriteBuffer(Header, SizeOf(Header));
  6884. end;
  6885. procedure EmptyOutputDir(const Log: Boolean);
  6886. procedure DelFile(const Filename: String);
  6887. begin
  6888. if DeleteFile(OutputDir + Filename) and Log then
  6889. AddStatus(Format(SCompilerStatusDeletingPrevious, [Filename]));
  6890. end;
  6891. var
  6892. H: THandle;
  6893. FindData: TWin32FindData;
  6894. N: String;
  6895. I: Integer;
  6896. HasNumbers: Boolean;
  6897. begin
  6898. { Delete SETUP.* and SETUP-*.BIN if they existed in the output directory }
  6899. if OutputBaseFilename <> '' then begin
  6900. DelFile(OutputBaseFilename + '.exe');
  6901. if OutputDir <> '' then begin
  6902. H := FindFirstFile(PChar(OutputDir + OutputBaseFilename + '-*.bin'), FindData);
  6903. if H <> INVALID_HANDLE_VALUE then begin
  6904. try
  6905. repeat
  6906. if FindData.dwFileAttributes and FILE_ATTRIBUTE_DIRECTORY = 0 then begin
  6907. N := FindData.cFileName;
  6908. if PathStartsWith(N, OutputBaseFilename) then begin
  6909. I := Length(OutputBaseFilename) + 1;
  6910. if (I <= Length(N)) and (N[I] = '-') then begin
  6911. Inc(I);
  6912. HasNumbers := False;
  6913. while (I <= Length(N)) and CharInSet(N[I], ['0'..'9']) do begin
  6914. HasNumbers := True;
  6915. Inc(I);
  6916. end;
  6917. if HasNumbers then begin
  6918. if (I <= Length(N)) and CharInSet(UpCase(N[I]), ['A'..'Z']) then
  6919. Inc(I);
  6920. if CompareText(Copy(N, I, Maxint), '.bin') = 0 then
  6921. DelFile(N);
  6922. end;
  6923. end;
  6924. end;
  6925. end;
  6926. until not FindNextFile(H, FindData);
  6927. finally
  6928. Windows.FindClose(H);
  6929. end;
  6930. end;
  6931. end;
  6932. end;
  6933. end;
  6934. procedure FreeListItems(const List: TList; const NumStrings, NumAnsiStrings: Integer);
  6935. var
  6936. I: Integer;
  6937. begin
  6938. for I := List.Count-1 downto 0 do begin
  6939. SEFreeRec(List[I], NumStrings, NumAnsiStrings);
  6940. List.Delete(I);
  6941. end;
  6942. end;
  6943. procedure FreePreLangData;
  6944. var
  6945. I: Integer;
  6946. begin
  6947. for I := PreLangDataList.Count-1 downto 0 do begin
  6948. TPreLangData(PreLangDataList[I]).Free;
  6949. PreLangDataList.Delete(I);
  6950. end;
  6951. end;
  6952. procedure FreeLangData;
  6953. var
  6954. I: Integer;
  6955. begin
  6956. for I := LangDataList.Count-1 downto 0 do begin
  6957. TLangData(LangDataList[I]).Free;
  6958. LangDataList.Delete(I);
  6959. end;
  6960. end;
  6961. procedure FreeScriptFiles;
  6962. var
  6963. I: Integer;
  6964. SL: TObject;
  6965. begin
  6966. for I := ScriptFiles.Count-1 downto 0 do begin
  6967. SL := ScriptFiles.Objects[I];
  6968. ScriptFiles.Delete(I);
  6969. SL.Free;
  6970. end;
  6971. end;
  6972. procedure FreeLineInfoList(L: TStringList);
  6973. var
  6974. I: Integer;
  6975. LineInfo: TLineInfo;
  6976. begin
  6977. for I := L.Count-1 downto 0 do begin
  6978. LineInfo := TLineInfo(L.Objects[I]);
  6979. L.Delete(I);
  6980. LineInfo.Free;
  6981. end;
  6982. end;
  6983. type
  6984. PCopyBuffer = ^TCopyBuffer;
  6985. TCopyBuffer = array[0..32767] of Char;
  6986. var
  6987. SetupFile: TFile;
  6988. ExeFile: TFile;
  6989. LicenseText, InfoBeforeText, InfoAfterText: AnsiString;
  6990. WizardImages, WizardSmallImages: TObjectList<TCustomMemoryStream>;
  6991. DecompressorDLL, DecryptionDLL: TMemoryStream;
  6992. SetupLdrOffsetTable: TSetupLdrOffsetTable;
  6993. SizeOfExe, SizeOfHeaders: Longint;
  6994. function WriteSetup0(const F: TFile): Longint;
  6995. procedure WriteStream(Stream: TCustomMemoryStream; W: TCompressedBlockWriter);
  6996. var
  6997. Size: Longint;
  6998. begin
  6999. Size := Stream.Size;
  7000. W.Write(Size, SizeOf(Size));
  7001. W.Write(Stream.Memory^, Size);
  7002. end;
  7003. var
  7004. Pos: Cardinal;
  7005. J: Integer;
  7006. W: TCompressedBlockWriter;
  7007. begin
  7008. Pos := F.Position.Lo;
  7009. F.WriteBuffer(SetupID, SizeOf(SetupID));
  7010. SetupHeader.NumLanguageEntries := LanguageEntries.Count;
  7011. SetupHeader.NumCustomMessageEntries := CustomMessageEntries.Count;
  7012. SetupHeader.NumPermissionEntries := PermissionEntries.Count;
  7013. SetupHeader.NumTypeEntries := TypeEntries.Count;
  7014. SetupHeader.NumComponentEntries := ComponentEntries.Count;
  7015. SetupHeader.NumTaskEntries := TaskEntries.Count;
  7016. SetupHeader.NumDirEntries := DirEntries.Count;
  7017. SetupHeader.NumFileEntries := FileEntries.Count;
  7018. SetupHeader.NumFileLocationEntries := FileLocationEntries.Count;
  7019. SetupHeader.NumIconEntries := IconEntries.Count;
  7020. SetupHeader.NumIniEntries := IniEntries.Count;
  7021. SetupHeader.NumRegistryEntries := RegistryEntries.Count;
  7022. SetupHeader.NumInstallDeleteEntries := InstallDeleteEntries.Count;
  7023. SetupHeader.NumUninstallDeleteEntries := UninstallDeleteEntries.Count;
  7024. SetupHeader.NumRunEntries := RunEntries.Count;
  7025. SetupHeader.NumUninstallRunEntries := UninstallRunEntries.Count;
  7026. SetupHeader.LicenseText := LicenseText;
  7027. SetupHeader.InfoBeforeText := InfoBeforeText;
  7028. SetupHeader.InfoAfterText := InfoAfterText;
  7029. SetupHeader.CompiledCodeText := CompiledCodeText;
  7030. W := TCompressedBlockWriter.Create(F, TLZMACompressor, InternalCompressLevel,
  7031. InternalCompressProps);
  7032. try
  7033. SECompressedBlockWrite(W, SetupHeader, SizeOf(SetupHeader),
  7034. SetupHeaderStrings, SetupHeaderAnsiStrings);
  7035. for J := 0 to LanguageEntries.Count-1 do
  7036. SECompressedBlockWrite(W, LanguageEntries[J]^, SizeOf(TSetupLanguageEntry),
  7037. SetupLanguageEntryStrings, SetupLanguageEntryAnsiStrings);
  7038. for J := 0 to CustomMessageEntries.Count-1 do
  7039. SECompressedBlockWrite(W, CustomMessageEntries[J]^, SizeOf(TSetupCustomMessageEntry),
  7040. SetupCustomMessageEntryStrings, SetupCustomMessageEntryAnsiStrings);
  7041. for J := 0 to PermissionEntries.Count-1 do
  7042. SECompressedBlockWrite(W, PermissionEntries[J]^, SizeOf(TSetupPermissionEntry),
  7043. SetupPermissionEntryStrings, SetupPermissionEntryAnsiStrings);
  7044. for J := 0 to TypeEntries.Count-1 do
  7045. SECompressedBlockWrite(W, TypeEntries[J]^, SizeOf(TSetupTypeEntry),
  7046. SetupTypeEntryStrings, SetupTypeEntryAnsiStrings);
  7047. for J := 0 to ComponentEntries.Count-1 do
  7048. SECompressedBlockWrite(W, ComponentEntries[J]^, SizeOf(TSetupComponentEntry),
  7049. SetupComponentEntryStrings, SetupComponentEntryAnsiStrings);
  7050. for J := 0 to TaskEntries.Count-1 do
  7051. SECompressedBlockWrite(W, TaskEntries[J]^, SizeOf(TSetupTaskEntry),
  7052. SetupTaskEntryStrings, SetupTaskEntryAnsiStrings);
  7053. for J := 0 to DirEntries.Count-1 do
  7054. SECompressedBlockWrite(W, DirEntries[J]^, SizeOf(TSetupDirEntry),
  7055. SetupDirEntryStrings, SetupDirEntryAnsiStrings);
  7056. for J := 0 to FileEntries.Count-1 do
  7057. SECompressedBlockWrite(W, FileEntries[J]^, SizeOf(TSetupFileEntry),
  7058. SetupFileEntryStrings, SetupFileEntryAnsiStrings);
  7059. for J := 0 to IconEntries.Count-1 do
  7060. SECompressedBlockWrite(W, IconEntries[J]^, SizeOf(TSetupIconEntry),
  7061. SetupIconEntryStrings, SetupIconEntryAnsiStrings);
  7062. for J := 0 to IniEntries.Count-1 do
  7063. SECompressedBlockWrite(W, IniEntries[J]^, SizeOf(TSetupIniEntry),
  7064. SetupIniEntryStrings, SetupIniEntryAnsiStrings);
  7065. for J := 0 to RegistryEntries.Count-1 do
  7066. SECompressedBlockWrite(W, RegistryEntries[J]^, SizeOf(TSetupRegistryEntry),
  7067. SetupRegistryEntryStrings, SetupRegistryEntryAnsiStrings);
  7068. for J := 0 to InstallDeleteEntries.Count-1 do
  7069. SECompressedBlockWrite(W, InstallDeleteEntries[J]^, SizeOf(TSetupDeleteEntry),
  7070. SetupDeleteEntryStrings, SetupDeleteEntryAnsiStrings);
  7071. for J := 0 to UninstallDeleteEntries.Count-1 do
  7072. SECompressedBlockWrite(W, UninstallDeleteEntries[J]^, SizeOf(TSetupDeleteEntry),
  7073. SetupDeleteEntryStrings, SetupDeleteEntryAnsiStrings);
  7074. for J := 0 to RunEntries.Count-1 do
  7075. SECompressedBlockWrite(W, RunEntries[J]^, SizeOf(TSetupRunEntry),
  7076. SetupRunEntryStrings, SetupRunEntryAnsiStrings);
  7077. for J := 0 to UninstallRunEntries.Count-1 do
  7078. SECompressedBlockWrite(W, UninstallRunEntries[J]^, SizeOf(TSetupRunEntry),
  7079. SetupRunEntryStrings, SetupRunEntryAnsiStrings);
  7080. W.Write(WizardImages.Count, SizeOf(Integer));
  7081. for J := 0 to WizardImages.Count-1 do
  7082. WriteStream(WizardImages[J], W);
  7083. W.Write(WizardSmallImages.Count, SizeOf(Integer));
  7084. for J := 0 to WizardSmallImages.Count-1 do
  7085. WriteStream(WizardSmallImages[J], W);
  7086. if SetupHeader.CompressMethod in [cmZip, cmBzip] then
  7087. WriteStream(DecompressorDLL, W);
  7088. if shEncryptionUsed in SetupHeader.Options then
  7089. WriteStream(DecryptionDLL, W);
  7090. W.Finish;
  7091. finally
  7092. W.Free;
  7093. end;
  7094. if not DiskSpanning then
  7095. W := TCompressedBlockWriter.Create(F, TLZMACompressor, InternalCompressLevel,
  7096. InternalCompressProps)
  7097. else
  7098. W := TCompressedBlockWriter.Create(F, nil, 0, nil);
  7099. { ^ When disk spanning is enabled, the Setup Compiler requires that
  7100. FileLocationEntries be a fixed size, so don't compress them }
  7101. try
  7102. for J := 0 to FileLocationEntries.Count-1 do
  7103. W.Write(FileLocationEntries[J]^, SizeOf(TSetupFileLocationEntry));
  7104. W.Finish;
  7105. finally
  7106. W.Free;
  7107. end;
  7108. Result := F.Position.Lo - Pos;
  7109. end;
  7110. function CreateSetup0File: Longint;
  7111. var
  7112. F: TFile;
  7113. begin
  7114. F := TFile.Create(OutputDir + OutputBaseFilename + '-0.bin',
  7115. fdCreateAlways, faWrite, fsNone);
  7116. try
  7117. Result := WriteSetup0(F);
  7118. finally
  7119. F.Free;
  7120. end;
  7121. end;
  7122. function RoundToNearestClusterSize(const L: Longint): Longint;
  7123. begin
  7124. Result := (L div DiskClusterSize) * DiskClusterSize;
  7125. if L mod DiskClusterSize <> 0 then
  7126. Inc(Result, DiskClusterSize);
  7127. end;
  7128. procedure CompressFiles(const FirstDestFile: String;
  7129. const BytesToReserveOnFirstDisk: Longint);
  7130. var
  7131. CurrentTime: TSystemTime;
  7132. procedure ApplyTouchDateTime(var FT: TFileTime);
  7133. var
  7134. ST: TSystemTime;
  7135. begin
  7136. if (TouchDateOption = tdNone) and (TouchTimeOption = ttNone) then
  7137. Exit; { nothing to do }
  7138. if not FileTimeToSystemTime(FT, ST) then
  7139. AbortCompile('ApplyTouch: FileTimeToSystemTime call failed');
  7140. case TouchDateOption of
  7141. tdCurrent: begin
  7142. ST.wYear := CurrentTime.wYear;
  7143. ST.wMonth := CurrentTime.wMonth;
  7144. ST.wDay := CurrentTime.wDay;
  7145. end;
  7146. tdExplicit: begin
  7147. ST.wYear := TouchDateYear;
  7148. ST.wMonth := TouchDateMonth;
  7149. ST.wDay := TouchDateDay;
  7150. end;
  7151. end;
  7152. case TouchTimeOption of
  7153. ttCurrent: begin
  7154. ST.wHour := CurrentTime.wHour;
  7155. ST.wMinute := CurrentTime.wMinute;
  7156. ST.wSecond := CurrentTime.wSecond;
  7157. ST.wMilliseconds := CurrentTime.wMilliseconds;
  7158. end;
  7159. ttExplicit: begin
  7160. ST.wHour := TouchTimeHour;
  7161. ST.wMinute := TouchTimeMinute;
  7162. ST.wSecond := TouchTimeSecond;
  7163. ST.wMilliseconds := 0;
  7164. end;
  7165. end;
  7166. if not SystemTimeToFileTime(ST, FT) then
  7167. AbortCompile('ApplyTouch: SystemTimeToFileTime call failed');
  7168. end;
  7169. function GetCompressorClass(const UseCompression: Boolean): TCustomCompressorClass;
  7170. begin
  7171. if not UseCompression then
  7172. Result := TStoredCompressor
  7173. else begin
  7174. case SetupHeader.CompressMethod of
  7175. cmStored: begin
  7176. Result := TStoredCompressor;
  7177. end;
  7178. cmZip: begin
  7179. InitZipDLL;
  7180. Result := TZCompressor;
  7181. end;
  7182. cmBzip: begin
  7183. InitBzipDLL;
  7184. Result := TBZCompressor;
  7185. end;
  7186. cmLZMA: begin
  7187. Result := TLZMACompressor;
  7188. end;
  7189. cmLZMA2: begin
  7190. Result := TLZMA2Compressor;
  7191. end;
  7192. else
  7193. AbortCompile('GetCompressorClass: Unknown CompressMethod');
  7194. Result := nil;
  7195. end;
  7196. end;
  7197. end;
  7198. procedure FinalizeChunk(const CH: TCompressionHandler;
  7199. const LastFileLocationEntry: Integer);
  7200. var
  7201. I: Integer;
  7202. FL: PSetupFileLocationEntry;
  7203. begin
  7204. if CH.ChunkStarted then begin
  7205. CH.EndChunk;
  7206. { Set LastSlice and ChunkCompressedSize on all file location
  7207. entries that are part of the chunk }
  7208. for I := 0 to LastFileLocationEntry do begin
  7209. FL := FileLocationEntries[I];
  7210. if (FL.StartOffset = CH.ChunkStartOffset) and (FL.FirstSlice = CH.ChunkFirstSlice) then begin
  7211. FL.LastSlice := CH.CurSlice;
  7212. FL.ChunkCompressedSize := CH.ChunkBytesWritten;
  7213. end;
  7214. end;
  7215. end;
  7216. end;
  7217. const
  7218. StatusFilesStoringOrCompressingVersionStrings: array [Boolean] of String = (
  7219. SCompilerStatusFilesStoringVersion,
  7220. SCompilerStatusFilesCompressingVersion);
  7221. StatusFilesStoringOrCompressingStrings: array [Boolean] of String = (
  7222. SCompilerStatusFilesStoring,
  7223. SCompilerStatusFilesCompressing);
  7224. var
  7225. CH: TCompressionHandler;
  7226. ChunkCompressed, DoSign: Boolean;
  7227. I: Integer;
  7228. FL: PSetupFileLocationEntry;
  7229. FT: TFileTime;
  7230. SourceFile: TFile;
  7231. SignatureAddress, SignatureSize: Cardinal;
  7232. HdrChecksum, ErrorCode: DWORD;
  7233. begin
  7234. if (SetupHeader.CompressMethod in [cmLZMA, cmLZMA2]) and
  7235. (CompressProps.WorkerProcessFilename <> '') then
  7236. AddStatus(Format(' Using separate process for LZMA compression (%s)',
  7237. [PathExtractName(CompressProps.WorkerProcessFilename)]));
  7238. if TimeStampsInUTC then
  7239. GetSystemTime(CurrentTime)
  7240. else
  7241. GetLocalTime(CurrentTime);
  7242. ChunkCompressed := False; { avoid warning }
  7243. CH := TCompressionHandler.Create(Self, FirstDestFile);
  7244. try
  7245. { If encryption is used, load the encryption DLL }
  7246. if shEncryptionUsed in SetupHeader.Options then begin
  7247. AddStatus(SCompilerStatusFilesInitEncryption);
  7248. InitCryptDLL;
  7249. end;
  7250. if DiskSpanning then begin
  7251. if not CH.ReserveBytesOnSlice(BytesToReserveOnFirstDisk) then
  7252. AbortCompile(SCompilerNotEnoughSpaceOnFirstDisk);
  7253. end;
  7254. CompressionStartTick := GetTickCount;
  7255. CompressionInProgress := True;
  7256. for I := 0 to FileLocationEntries.Count-1 do begin
  7257. FL := FileLocationEntries[I];
  7258. if (foSign in FL.Flags) or (foSignOnce in FL.Flags) then begin
  7259. if (foSignOnce in FL.Flags) then begin
  7260. SourceFile := TFile.Create(FileLocationEntryFilenames[I],
  7261. fdOpenExisting, faRead, fsRead);
  7262. try
  7263. { Check the file for a signature }
  7264. if ReadSignatureAndChecksumFields(SourceFile, DWORD(SignatureAddress),
  7265. DWORD(SignatureSize), HdrChecksum) or
  7266. ReadSignatureAndChecksumFields64(SourceFile, DWORD(SignatureAddress),
  7267. DWORD(SignatureSize), HdrChecksum) then
  7268. DoSign := SignatureSize = 0
  7269. else
  7270. DoSign := True; { Couldn't check the file, try sign anyway and let the sign tool tell user what is wrong }
  7271. finally
  7272. SourceFile.Free;
  7273. end;
  7274. end else
  7275. DoSign := True;
  7276. if DoSign then begin
  7277. AddStatus(Format(SCompilerStatusSigningSourceFile, [FileLocationEntryFilenames[I]]));
  7278. Sign(FileLocationEntryFilenames[I]);
  7279. CallIdleProc;
  7280. end else
  7281. AddStatus(Format(SCompilerStatusSourceFileAlreadySigned, [FileLocationEntryFilenames[I]]));
  7282. end;
  7283. if foVersionInfoValid in FL.Flags then
  7284. AddStatus(Format(StatusFilesStoringOrCompressingVersionStrings[foChunkCompressed in FL.Flags],
  7285. [FileLocationEntryFilenames[I],
  7286. LongRec(FL.FileVersionMS).Hi, LongRec(FL.FileVersionMS).Lo,
  7287. LongRec(FL.FileVersionLS).Hi, LongRec(FL.FileVersionLS).Lo]))
  7288. else
  7289. AddStatus(Format(StatusFilesStoringOrCompressingStrings[foChunkCompressed in FL.Flags],
  7290. [FileLocationEntryFilenames[I]]));
  7291. CallIdleProc;
  7292. SourceFile := TFile.Create(FileLocationEntryFilenames[I],
  7293. fdOpenExisting, faRead, fsRead);
  7294. try
  7295. if CH.ChunkStarted then begin
  7296. { End the current chunk if one of the following conditions is true:
  7297. - we're not using solid compression
  7298. - the "solidbreak" flag was specified on this file
  7299. - the compression or encryption status of this file is
  7300. different from the previous file(s) in the chunk }
  7301. if not UseSolidCompression or
  7302. (foSolidBreak in FL.Flags) or
  7303. (ChunkCompressed <> (foChunkCompressed in FL.Flags)) or
  7304. (CH.ChunkEncrypted <> (foChunkEncrypted in FL.Flags)) then
  7305. FinalizeChunk(CH, I-1);
  7306. end;
  7307. { Start a new chunk if needed }
  7308. if not CH.ChunkStarted then begin
  7309. ChunkCompressed := (foChunkCompressed in FL.Flags);
  7310. CH.NewChunk(GetCompressorClass(ChunkCompressed), CompressLevel,
  7311. CompressProps, foChunkEncrypted in FL.Flags, CryptKey);
  7312. end;
  7313. FL.FirstSlice := CH.ChunkFirstSlice;
  7314. FL.StartOffset := CH.ChunkStartOffset;
  7315. FL.ChunkSuboffset := CH.ChunkBytesRead;
  7316. FL.OriginalSize := SourceFile.Size;
  7317. if not GetFileTime(SourceFile.Handle, nil, nil, @FT) then begin
  7318. ErrorCode := GetLastError;
  7319. AbortCompileFmt(SCompilerFunctionFailedWithCode,
  7320. ['CompressFiles: GetFileTime', ErrorCode, Win32ErrorString(ErrorCode)]);
  7321. end;
  7322. if TimeStampsInUTC then begin
  7323. FL.SourceTimeStamp := FT;
  7324. Include(FL.Flags, foTimeStampInUTC);
  7325. end
  7326. else
  7327. FileTimeToLocalFileTime(FT, FL.SourceTimeStamp);
  7328. if foApplyTouchDateTime in FL.Flags then
  7329. ApplyTouchDateTime(FL.SourceTimeStamp);
  7330. if TimeStampRounding > 0 then
  7331. Dec64(Integer64(FL.SourceTimeStamp), Mod64(Integer64(FL.SourceTimeStamp), TimeStampRounding * 10000000));
  7332. if ChunkCompressed and IsX86OrX64Executable(SourceFile) then
  7333. Include(FL.Flags, foCallInstructionOptimized);
  7334. CH.CompressFile(SourceFile, FL.OriginalSize,
  7335. foCallInstructionOptimized in FL.Flags, FL.SHA1Sum);
  7336. finally
  7337. SourceFile.Free;
  7338. end;
  7339. end;
  7340. { Finalize the last chunk }
  7341. FinalizeChunk(CH, FileLocationEntries.Count-1);
  7342. CH.Finish;
  7343. finally
  7344. CompressionInProgress := False;
  7345. CH.Free;
  7346. end;
  7347. { Ensure progress bar is full, in case a file shrunk in size }
  7348. BytesCompressedSoFar := TotalBytesToCompress;
  7349. CallIdleProc;
  7350. end;
  7351. procedure CopyFileOrAbort(const SourceFile, DestFile: String);
  7352. var
  7353. ErrorCode: DWORD;
  7354. begin
  7355. if not CopyFile(PChar(SourceFile), PChar(DestFile), False) then begin
  7356. ErrorCode := GetLastError;
  7357. AbortCompileFmt(SCompilerCopyError3, [SourceFile, DestFile,
  7358. ErrorCode, Win32ErrorString(ErrorCode)]);
  7359. end;
  7360. end;
  7361. function InternalSignSetupE32(const Filename: String;
  7362. var UnsignedFile: TMemoryFile; const UnsignedFileSize: Cardinal;
  7363. const MismatchMessage: String): Boolean;
  7364. var
  7365. SignedFile, TestFile, OldFile: TMemoryFile;
  7366. SignedFileSize: Cardinal;
  7367. SignatureAddress, SignatureSize: Cardinal;
  7368. HdrChecksum: DWORD;
  7369. begin
  7370. SignedFile := TMemoryFile.Create(Filename);
  7371. try
  7372. SignedFileSize := SignedFile.CappedSize;
  7373. { Check the file for a signature }
  7374. if not ReadSignatureAndChecksumFields(SignedFile, DWORD(SignatureAddress),
  7375. DWORD(SignatureSize), HdrChecksum) then
  7376. AbortCompile('ReadSignatureAndChecksumFields failed');
  7377. if SignatureAddress = 0 then begin
  7378. { No signature found. Return False to inform the caller that the file
  7379. needs to be signed, but first make sure it isn't somehow corrupted. }
  7380. if (SignedFileSize = UnsignedFileSize) and
  7381. CompareMem(UnsignedFile.Memory, SignedFile.Memory, UnsignedFileSize) then begin
  7382. Result := False;
  7383. Exit;
  7384. end;
  7385. AbortCompileFmt(MismatchMessage, [Filename]);
  7386. end;
  7387. if (SignedFileSize <= UnsignedFileSize) or
  7388. (SignatureAddress <> UnsignedFileSize) or
  7389. (SignatureSize <> SignedFileSize - UnsignedFileSize) or
  7390. (SignatureSize >= Cardinal($100000)) then
  7391. AbortCompile(SCompilerSignatureInvalid);
  7392. { Sanity check: Remove the signature (in memory) and verify that
  7393. the signed file is identical byte-for-byte to the original }
  7394. TestFile := TMemoryFile.CreateFromMemory(SignedFile.Memory^, SignedFileSize);
  7395. try
  7396. { Carry checksum over from UnsignedFile to TestFile. We used to just
  7397. zero it in TestFile, but that didn't work if the user modified
  7398. Setup.e32 with a res-editing tool that sets a non-zero checksum. }
  7399. if not ReadSignatureAndChecksumFields(UnsignedFile, DWORD(SignatureAddress),
  7400. DWORD(SignatureSize), HdrChecksum) then
  7401. AbortCompile('ReadSignatureAndChecksumFields failed (2)');
  7402. if not UpdateSignatureAndChecksumFields(TestFile, 0, 0, HdrChecksum) then
  7403. AbortCompile('UpdateSignatureAndChecksumFields failed');
  7404. if not CompareMem(UnsignedFile.Memory, TestFile.Memory, UnsignedFileSize) then
  7405. AbortCompileFmt(MismatchMessage, [Filename]);
  7406. finally
  7407. TestFile.Free;
  7408. end;
  7409. except
  7410. SignedFile.Free;
  7411. raise;
  7412. end;
  7413. { Replace UnsignedFile with the signed file }
  7414. OldFile := UnsignedFile;
  7415. UnsignedFile := SignedFile;
  7416. OldFile.Free;
  7417. Result := True;
  7418. end;
  7419. procedure SignSetupE32(var UnsignedFile: TMemoryFile);
  7420. var
  7421. UnsignedFileSize: Cardinal;
  7422. ModeID: Longint;
  7423. Filename, TempFilename: String;
  7424. F: TFile;
  7425. LastError: DWORD;
  7426. begin
  7427. UnsignedFileSize := UnsignedFile.CappedSize;
  7428. UnsignedFile.Seek(SetupExeModeOffset);
  7429. ModeID := SetupExeModeUninstaller;
  7430. UnsignedFile.WriteBuffer(ModeID, SizeOf(ModeID));
  7431. if SignTools.Count > 0 then begin
  7432. Filename := SignedUninstallerDir + 'uninst.e32.tmp';
  7433. F := TFile.Create(Filename, fdCreateAlways, faWrite, fsNone);
  7434. try
  7435. F.WriteBuffer(UnsignedFile.Memory^, UnsignedFileSize);
  7436. finally
  7437. F.Free;
  7438. end;
  7439. try
  7440. Sign(Filename);
  7441. if not InternalSignSetupE32(Filename, UnsignedFile, UnsignedFileSize,
  7442. SCompilerSignedFileContentsMismatch) then
  7443. AbortCompile(SCompilerSignToolSucceededButNoSignature);
  7444. finally
  7445. DeleteFile(Filename);
  7446. end;
  7447. end else begin
  7448. Filename := SignedUninstallerDir + Format('uninst-%s-%s.e32', [SetupVersion,
  7449. Copy(SHA1DigestToString(SHA1Buf(UnsignedFile.Memory^, UnsignedFileSize)), 1, 10)]);
  7450. if not NewFileExists(Filename) then begin
  7451. { Create new signed uninstaller file }
  7452. AddStatus(Format(SCompilerStatusSignedUninstallerNew, [Filename]));
  7453. TempFilename := Filename + '.tmp';
  7454. F := TFile.Create(TempFilename, fdCreateAlways, faWrite, fsNone);
  7455. try
  7456. F.WriteBuffer(UnsignedFile.Memory^, UnsignedFileSize);
  7457. finally
  7458. F.Free;
  7459. end;
  7460. if not MoveFile(PChar(TempFilename), PChar(Filename)) then begin
  7461. LastError := GetLastError;
  7462. DeleteFile(TempFilename);
  7463. TFile.RaiseError(LastError);
  7464. end;
  7465. end
  7466. else begin
  7467. { Use existing signed uninstaller file }
  7468. AddStatus(Format(SCompilerStatusSignedUninstallerExisting, [Filename]));
  7469. end;
  7470. if not InternalSignSetupE32(Filename, UnsignedFile, UnsignedFileSize,
  7471. SCompilerSignedFileContentsMismatchRetry) then
  7472. AbortCompileFmt(SCompilerSignatureNeeded, [Filename]);
  7473. end;
  7474. end;
  7475. procedure PrepareSetupE32(var M: TMemoryFile);
  7476. var
  7477. TempFilename, E32Filename, ConvertFilename: String;
  7478. ConvertFile: TFile;
  7479. begin
  7480. TempFilename := '';
  7481. try
  7482. E32Filename := CompilerDir + 'SETUP.E32';
  7483. { make a copy and update icons, version info and if needed manifest }
  7484. ConvertFilename := OutputDir + OutputBaseFilename + '.e32.tmp';
  7485. CopyFileOrAbort(E32Filename, ConvertFilename);
  7486. SetFileAttributes(PChar(ConvertFilename), FILE_ATTRIBUTE_ARCHIVE);
  7487. TempFilename := ConvertFilename;
  7488. if SetupIconFilename <> '' then begin
  7489. AddStatus(Format(SCompilerStatusUpdatingIcons, ['SETUP.E32']));
  7490. LineNumber := SetupDirectiveLines[ssSetupIconFile];
  7491. { This also deletes the UninstallImage resource. Removing it makes UninstallProgressForm use the custom icon instead. }
  7492. UpdateIcons(ConvertFileName, PrependSourceDirName(SetupIconFilename), True);
  7493. LineNumber := 0;
  7494. end;
  7495. AddStatus(Format(SCompilerStatusUpdatingVersionInfo, ['SETUP.E32']));
  7496. ConvertFile := TFile.Create(ConvertFilename, fdOpenExisting, faReadWrite, fsNone);
  7497. try
  7498. UpdateVersionInfo(ConvertFile, TFileVersionNumbers(nil^), VersionInfoProductVersion, VersionInfoCompany,
  7499. '', '', VersionInfoCopyright, VersionInfoProductName, VersionInfoProductTextVersion, VersionInfoOriginalFileName,
  7500. False);
  7501. finally
  7502. ConvertFile.Free;
  7503. end;
  7504. M := TMemoryFile.Create(ConvertFilename);
  7505. UpdateSetupPEHeaderFields(M, TerminalServicesAware, DEPCompatible, ASLRCompatible);
  7506. if shSignedUninstaller in SetupHeader.Options then
  7507. SignSetupE32(M);
  7508. finally
  7509. if TempFilename <> '' then
  7510. DeleteFile(TempFilename);
  7511. end;
  7512. end;
  7513. procedure CompressSetupE32(const M: TMemoryFile; const DestF: TFile;
  7514. var UncompressedSize: LongWord; var CRC: Longint);
  7515. { Note: This modifies the contents of M. }
  7516. var
  7517. Writer: TCompressedBlockWriter;
  7518. begin
  7519. AddStatus(SCompilerStatusCompressingSetupExe);
  7520. UncompressedSize := M.CappedSize;
  7521. CRC := GetCRC32(M.Memory^, UncompressedSize);
  7522. TransformCallInstructions(M.Memory^, UncompressedSize, True, 0);
  7523. Writer := TCompressedBlockWriter.Create(DestF, TLZMACompressor, InternalCompressLevel,
  7524. InternalCompressProps);
  7525. try
  7526. Writer.Write(M.Memory^, UncompressedSize);
  7527. Writer.Finish;
  7528. finally
  7529. Writer.Free;
  7530. end;
  7531. end;
  7532. procedure AddDefaultSetupType(Name: String; Options: TSetupTypeOptions; Typ: TSetupTypeType);
  7533. var
  7534. NewTypeEntry: PSetupTypeEntry;
  7535. begin
  7536. NewTypeEntry := AllocMem(SizeOf(TSetupTypeEntry));
  7537. NewTypeEntry.Name := Name;
  7538. NewTypeEntry.Description := ''; //set at runtime
  7539. NewTypeEntry.Check := '';
  7540. NewTypeEntry.MinVersion := SetupHeader.MinVersion;
  7541. NewTypeEntry.OnlyBelowVersion := SetupHeader.OnlyBelowVersion;
  7542. NewTypeEntry.Options := Options;
  7543. NewTypeEntry.Typ := Typ;
  7544. TypeEntries.Add(NewTypeEntry);
  7545. end;
  7546. procedure MkDirs(Dir: string);
  7547. begin
  7548. Dir := RemoveBackslashUnlessRoot(Dir);
  7549. if (PathExtractPath(Dir) = Dir) or DirExists(Dir) then
  7550. Exit;
  7551. MkDirs(PathExtractPath(Dir));
  7552. MkDir(Dir);
  7553. end;
  7554. procedure CreateManifestFile;
  7555. function FileTimeToString(const FileTime: TFileTime; const UTC: Boolean): String;
  7556. var
  7557. ST: TSystemTime;
  7558. begin
  7559. if FileTimeToSystemTime(FileTime, ST) then
  7560. Result := Format('%.4u-%.2u-%.2u %.2u:%.2u:%.2u.%.3u',
  7561. [ST.wYear, ST.wMonth, ST.wDay, ST.wHour, ST.wMinute, ST.wSecond,
  7562. ST.wMilliseconds])
  7563. else
  7564. Result := '(invalid)';
  7565. if UTC then
  7566. Result := Result + ' UTC';
  7567. end;
  7568. function SliceToString(const ASlice: Integer): String;
  7569. begin
  7570. Result := IntToStr(ASlice div SlicesPerDisk + 1);
  7571. if SlicesPerDisk <> 1 then
  7572. Result := Result + Chr(Ord('a') + ASlice mod SlicesPerDisk);
  7573. end;
  7574. const
  7575. EncryptedStrings: array [Boolean] of String = ('no', 'yes');
  7576. var
  7577. F: TTextFileWriter;
  7578. FL: PSetupFileLocationEntry;
  7579. S: String;
  7580. I: Integer;
  7581. begin
  7582. F := TTextFileWriter.Create(PrependDirName(OutputManifestFile, OutputDir),
  7583. fdCreateAlways, faWrite, fsRead);
  7584. try
  7585. S := 'Index' + #9 + 'SourceFilename' + #9 + 'TimeStamp' + #9 +
  7586. 'Version' + #9 + 'SHA1Sum' + #9 + 'OriginalSize' + #9 +
  7587. 'FirstSlice' + #9 + 'LastSlice' + #9 + 'StartOffset' + #9 +
  7588. 'ChunkSuboffset' + #9 + 'ChunkCompressedSize' + #9 + 'Encrypted';
  7589. F.WriteLine(S);
  7590. for I := 0 to FileLocationEntries.Count-1 do begin
  7591. FL := FileLocationEntries[I];
  7592. S := IntToStr(I) + #9 + FileLocationEntryFilenames[I] + #9 +
  7593. FileTimeToString(FL.SourceTimeStamp, foTimeStampInUTC in FL.Flags) + #9;
  7594. if foVersionInfoValid in FL.Flags then
  7595. S := S + Format('%u.%u.%u.%u', [FL.FileVersionMS shr 16,
  7596. FL.FileVersionMS and $FFFF, FL.FileVersionLS shr 16,
  7597. FL.FileVersionLS and $FFFF]);
  7598. S := S + #9 + SHA1DigestToString(FL.SHA1Sum) + #9 +
  7599. Integer64ToStr(FL.OriginalSize) + #9 +
  7600. SliceToString(FL.FirstSlice) + #9 +
  7601. SliceToString(FL.LastSlice) + #9 +
  7602. IntToStr(FL.StartOffset) + #9 +
  7603. Integer64ToStr(FL.ChunkSuboffset) + #9 +
  7604. Integer64ToStr(FL.ChunkCompressedSize) + #9 +
  7605. EncryptedStrings[foChunkEncrypted in FL.Flags];
  7606. F.WriteLine(S);
  7607. end;
  7608. finally
  7609. F.Free;
  7610. end;
  7611. end;
  7612. procedure CallPreprocessorCleanupProc;
  7613. var
  7614. ResultCode: Integer;
  7615. begin
  7616. if Assigned(PreprocCleanupProc) then begin
  7617. ResultCode := PreprocCleanupProc(PreprocCleanupProcData);
  7618. if ResultCode <> 0 then
  7619. AddStatusFmt(SCompilerStatusWarning +
  7620. 'Preprocessor cleanup function failed with code %d.', [ResultCode], True);
  7621. end;
  7622. end;
  7623. const
  7624. BadFilePathChars = '/*?"<>|';
  7625. BadFileNameChars = BadFilePathChars + ':';
  7626. var
  7627. SetupE32: TMemoryFile;
  7628. I: Integer;
  7629. AppNameHasConsts, AppVersionHasConsts, AppPublisherHasConsts,
  7630. AppCopyrightHasConsts, AppIdHasConsts, Uninstallable: Boolean;
  7631. PrivilegesRequiredValue: String;
  7632. begin
  7633. { Sanity check: A single TSetupCompiler instance cannot be used to do
  7634. multiple compiles. A separate instance must be used for each compile,
  7635. otherwise some settings (e.g. DefaultLangData, VersionInfo*) would be
  7636. carried over from one compile to another. }
  7637. if CompileWasAlreadyCalled then
  7638. AbortCompile('Compile was already called');
  7639. CompileWasAlreadyCalled := True;
  7640. CompilerDir := AddBackslash(PathExpand(CompilerDir));
  7641. InitPreprocessor;
  7642. InitLZMADLL;
  7643. WizardImages := nil;
  7644. WizardSmallImages := nil;
  7645. SetupE32 := nil;
  7646. DecompressorDLL := nil;
  7647. DecryptionDLL := nil;
  7648. try
  7649. Finalize(SetupHeader);
  7650. FillChar(SetupHeader, SizeOf(SetupHeader), 0);
  7651. InitDebugInfo;
  7652. PreprocIncludedFilenames.Clear;
  7653. { Initialize defaults }
  7654. OriginalSourceDir := AddBackslash(PathExpand(SourceDir));
  7655. if not FixedOutput then
  7656. Output := True;
  7657. if not FixedOutputDir then
  7658. OutputDir := 'Output';
  7659. if not FixedOutputBaseFilename then
  7660. OutputBaseFilename := 'mysetup';
  7661. InternalCompressLevel := clLZMANormal;
  7662. InternalCompressProps := TLZMACompressorProps.Create;
  7663. CompressMethod := cmLZMA2;
  7664. CompressLevel := clLZMAMax;
  7665. CompressProps := TLZMACompressorProps.Create;
  7666. UseSetupLdr := True;
  7667. TerminalServicesAware := True;
  7668. DEPCompatible := True;
  7669. ASLRCompatible := True;
  7670. DiskSliceSize := MaxDiskSliceSize;
  7671. DiskClusterSize := 512;
  7672. SlicesPerDisk := 1;
  7673. ReserveBytes := 0;
  7674. TimeStampRounding := 2;
  7675. SetupHeader.MinVersion.WinVersion := 0;
  7676. SetupHeader.MinVersion.NTVersion := $06010000;
  7677. SetupHeader.MinVersion.NTServicePack := $100;
  7678. SetupHeader.Options := [shDisableStartupPrompt, shCreateAppDir,
  7679. shWindowStartMaximized, shWindowShowCaption, shWindowResizable,
  7680. shUsePreviousAppDir, shUsePreviousGroup,
  7681. shUsePreviousSetupType, shAlwaysShowComponentsList, shFlatComponentsList,
  7682. shShowComponentSizes, shUsePreviousTasks, shUpdateUninstallLogAppName,
  7683. shAllowUNCPath, shUsePreviousUserInfo, shRestartIfNeededByRun,
  7684. shAllowCancelDuringInstall, shWizardImageStretch, shAppendDefaultDirName,
  7685. shAppendDefaultGroupName, shUsePreviousLanguage, shCloseApplications,
  7686. shRestartApplications, shAllowNetworkDrive, shDisableWelcomePage,
  7687. shUsePreviousPrivileges];
  7688. SetupHeader.PrivilegesRequired := prAdmin;
  7689. SetupHeader.UninstallFilesDir := '{app}';
  7690. SetupHeader.DefaultUserInfoName := '{sysuserinfoname}';
  7691. SetupHeader.DefaultUserInfoOrg := '{sysuserinfoorg}';
  7692. SetupHeader.BackColor := clBlue;
  7693. SetupHeader.BackColor2 := clBlack;
  7694. SetupHeader.DisableDirPage := dpAuto;
  7695. SetupHeader.DisableProgramGroupPage := dpAuto;
  7696. SetupHeader.CreateUninstallRegKey := 'yes';
  7697. SetupHeader.Uninstallable := 'yes';
  7698. SetupHeader.ChangesEnvironment := 'no';
  7699. SetupHeader.ChangesAssociations := 'no';
  7700. BackSolid := False;
  7701. DefaultDialogFontName := 'Tahoma';
  7702. SignToolRetryCount := 2;
  7703. SignToolRetryDelay := 500;
  7704. SetupHeader.CloseApplicationsFilter := '*.exe,*.dll,*.chm';
  7705. SetupHeader.WizardImageAlphaFormat := afIgnored;
  7706. MissingRunOnceIdsWarning := True;
  7707. MissingMessagesWarning := True;
  7708. NotRecognizedMessagesWarning := True;
  7709. UsedUserAreasWarning := True;
  7710. SetupHeader.WizardStyle := wsClassic;
  7711. { Read [Setup] section }
  7712. EnumIniSection(EnumSetupProc, 'Setup', 0, True, True, '', False, False);
  7713. CallIdleProc;
  7714. { Verify settings set in [Setup] section }
  7715. if SetupDirectiveLines[ssAppName] = 0 then
  7716. AbortCompileFmt(SCompilerEntryMissing2, ['Setup', 'AppName']);
  7717. if (SetupHeader.AppVerName = '') and (SetupHeader.AppVersion = '') then
  7718. AbortCompile(SCompilerAppVersionOrAppVerNameRequired);
  7719. LineNumber := SetupDirectiveLines[ssAppName];
  7720. AppNameHasConsts := CheckConst(SetupHeader.AppName, SetupHeader.MinVersion, []);
  7721. if AppNameHasConsts then begin
  7722. Include(SetupHeader.Options, shAppNameHasConsts);
  7723. if not(shDisableStartupPrompt in SetupHeader.Options) then begin
  7724. { AppName has constants so DisableStartupPrompt must be used }
  7725. LineNumber := SetupDirectiveLines[ssDisableStartupPrompt];
  7726. AbortCompile(SCompilerMustUseDisableStartupPrompt);
  7727. end;
  7728. end;
  7729. if SetupHeader.AppId = '' then
  7730. SetupHeader.AppId := SetupHeader.AppName
  7731. else
  7732. LineNumber := SetupDirectiveLines[ssAppId];
  7733. AppIdHasConsts := CheckConst(SetupHeader.AppId, SetupHeader.MinVersion, []);
  7734. if AppIdHasConsts and (shUsePreviousLanguage in SetupHeader.Options) then begin
  7735. { AppId has constants so UsePreviousLanguage must not be used }
  7736. LineNumber := SetupDirectiveLines[ssUsePreviousLanguage];
  7737. AbortCompile(SCompilerMustNotUsePreviousLanguage);
  7738. end;
  7739. if AppIdHasConsts and (proDialog in SetupHeader.PrivilegesRequiredOverridesAllowed) and (shUsePreviousPrivileges in SetupHeader.Options) then begin
  7740. { AppId has constants so UsePreviousPrivileges must not be used }
  7741. LineNumber := SetupDirectiveLines[ssUsePreviousPrivileges];
  7742. AbortCompile(SCompilerMustNotUsePreviousPrivileges);
  7743. end;
  7744. LineNumber := SetupDirectiveLines[ssAppVerName];
  7745. CheckConst(SetupHeader.AppVerName, SetupHeader.MinVersion, []);
  7746. LineNumber := SetupDirectiveLines[ssAppComments];
  7747. CheckConst(SetupHeader.AppComments, SetupHeader.MinVersion, []);
  7748. LineNumber := SetupDirectiveLines[ssAppContact];
  7749. CheckConst(SetupHeader.AppContact, SetupHeader.MinVersion, []);
  7750. LineNumber := SetupDirectiveLines[ssAppCopyright];
  7751. AppCopyrightHasConsts := CheckConst(SetupHeader.AppCopyright, SetupHeader.MinVersion, []);
  7752. LineNumber := SetupDirectiveLines[ssAppModifyPath];
  7753. CheckConst(SetupHeader.AppModifyPath, SetupHeader.MinVersion, []);
  7754. LineNumber := SetupDirectiveLines[ssAppPublisher];
  7755. AppPublisherHasConsts := CheckConst(SetupHeader.AppPublisher, SetupHeader.MinVersion, []);
  7756. LineNumber := SetupDirectiveLines[ssAppPublisherURL];
  7757. CheckConst(SetupHeader.AppPublisherURL, SetupHeader.MinVersion, []);
  7758. LineNumber := SetupDirectiveLines[ssAppReadmeFile];
  7759. CheckConst(SetupHeader.AppReadmeFile, SetupHeader.MinVersion, []);
  7760. LineNumber := SetupDirectiveLines[ssAppSupportPhone];
  7761. CheckConst(SetupHeader.AppSupportPhone, SetupHeader.MinVersion, []);
  7762. LineNumber := SetupDirectiveLines[ssAppSupportURL];
  7763. CheckConst(SetupHeader.AppSupportURL, SetupHeader.MinVersion, []);
  7764. LineNumber := SetupDirectiveLines[ssAppUpdatesURL];
  7765. CheckConst(SetupHeader.AppUpdatesURL, SetupHeader.MinVersion, []);
  7766. LineNumber := SetupDirectiveLines[ssAppVersion];
  7767. AppVersionHasConsts := CheckConst(SetupHeader.AppVersion, SetupHeader.MinVersion, []);
  7768. LineNumber := SetupDirectiveLines[ssAppMutex];
  7769. CheckConst(SetupHeader.AppMutex, SetupHeader.MinVersion, []);
  7770. LineNumber := SetupDirectiveLines[ssSetupMutex];
  7771. CheckConst(SetupHeader.SetupMutex, SetupHeader.MinVersion, []);
  7772. LineNumber := SetupDirectiveLines[ssDefaultDirName];
  7773. CheckConst(SetupHeader.DefaultDirName, SetupHeader.MinVersion, []);
  7774. if SetupHeader.DefaultDirName = '' then begin
  7775. if shCreateAppDir in SetupHeader.Options then
  7776. AbortCompileFmt(SCompilerEntryMissing2, ['Setup', 'DefaultDirName'])
  7777. else
  7778. SetupHeader.DefaultDirName := '?ERROR?';
  7779. end;
  7780. LineNumber := SetupDirectiveLines[ssDefaultGroupName];
  7781. CheckConst(SetupHeader.DefaultGroupName, SetupHeader.MinVersion, []);
  7782. if SetupHeader.DefaultGroupName = '' then
  7783. SetupHeader.DefaultGroupName := '(Default)';
  7784. LineNumber := SetupDirectiveLines[ssUninstallDisplayName];
  7785. CheckConst(SetupHeader.UninstallDisplayName, SetupHeader.MinVersion, []);
  7786. LineNumber := SetupDirectiveLines[ssUninstallDisplayIcon];
  7787. CheckConst(SetupHeader.UninstallDisplayIcon, SetupHeader.MinVersion, []);
  7788. LineNumber := SetupDirectiveLines[ssUninstallFilesDir];
  7789. CheckConst(SetupHeader.UninstallFilesDir, SetupHeader.MinVersion, []);
  7790. LineNumber := SetupDirectiveLines[ssDefaultUserInfoName];
  7791. CheckConst(SetupHeader.DefaultUserInfoName, SetupHeader.MinVersion, []);
  7792. LineNumber := SetupDirectiveLines[ssDefaultUserInfoOrg];
  7793. CheckConst(SetupHeader.DefaultUserInfoOrg, SetupHeader.MinVersion, []);
  7794. LineNumber := SetupDirectiveLines[ssDefaultUserInfoSerial];
  7795. CheckConst(SetupHeader.DefaultUserInfoSerial, SetupHeader.MinVersion, []);
  7796. if BackSolid then
  7797. SetupHeader.BackColor2 := SetupHeader.BackColor;
  7798. if not DiskSpanning then begin
  7799. DiskSliceSize := MaxDiskSliceSize;
  7800. DiskClusterSize := 1;
  7801. SlicesPerDisk := 1;
  7802. ReserveBytes := 0;
  7803. end;
  7804. SetupHeader.SlicesPerDisk := SlicesPerDisk;
  7805. if SetupDirectiveLines[ssVersionInfoDescription] = 0 then begin
  7806. { Use AppName as VersionInfoDescription if possible. If not possible,
  7807. warn about this since AppName is a required directive }
  7808. if not AppNameHasConsts then
  7809. VersionInfoDescription := UnescapeBraces(SetupHeader.AppName) + ' Setup'
  7810. else
  7811. WarningsList.Add(Format(SCompilerDirectiveNotUsingDefault,
  7812. ['VersionInfoDescription', 'AppName']));
  7813. end;
  7814. if SetupDirectiveLines[ssVersionInfoCompany] = 0 then begin
  7815. { Use AppPublisher as VersionInfoCompany if possible, otherwise warn }
  7816. if not AppPublisherHasConsts then
  7817. VersionInfoCompany := UnescapeBraces(SetupHeader.AppPublisher)
  7818. else
  7819. WarningsList.Add(Format(SCompilerDirectiveNotUsingDefault,
  7820. ['VersionInfoCompany', 'AppPublisher']));
  7821. end;
  7822. if SetupDirectiveLines[ssVersionInfoCopyright] = 0 then begin
  7823. { Use AppCopyright as VersionInfoCopyright if possible, otherwise warn }
  7824. if not AppCopyrightHasConsts then
  7825. VersionInfoCopyright := UnescapeBraces(SetupHeader.AppCopyright)
  7826. else
  7827. WarningsList.Add(Format(SCompilerDirectiveNotUsingDefault,
  7828. ['VersionInfoCopyright', 'AppCopyright']));
  7829. end;
  7830. if SetupDirectiveLines[ssVersionInfoTextVersion] = 0 then
  7831. VersionInfoTextVersion := VersionInfoVersionOriginalValue;
  7832. if SetupDirectiveLines[ssVersionInfoProductName] = 0 then begin
  7833. { Use AppName as VersionInfoProductName if possible, otherwise warn }
  7834. if not AppNameHasConsts then
  7835. VersionInfoProductName := UnescapeBraces(SetupHeader.AppName)
  7836. else
  7837. WarningsList.Add(Format(SCompilerDirectiveNotUsingDefault,
  7838. ['VersionInfoProductName', 'AppName']));
  7839. end;
  7840. if VersionInfoProductVersionOriginalValue = '' then
  7841. VersionInfoProductVersion := VersionInfoVersion;
  7842. if SetupDirectiveLines[ssVersionInfoProductTextVersion] = 0 then begin
  7843. { Note: This depends on the initialization of VersionInfoTextVersion above }
  7844. if VersionInfoProductVersionOriginalValue = '' then begin
  7845. VersionInfoProductTextVersion := VersionInfoTextVersion;
  7846. if SetupHeader.AppVersion <> '' then begin
  7847. if not AppVersionHasConsts then
  7848. VersionInfoProductTextVersion := UnescapeBraces(SetupHeader.AppVersion)
  7849. else
  7850. WarningsList.Add(Format(SCompilerDirectiveNotUsingPreferredDefault,
  7851. ['VersionInfoProductTextVersion', 'VersionInfoTextVersion', 'AppVersion']));
  7852. end;
  7853. end
  7854. else
  7855. VersionInfoProductTextVersion := VersionInfoProductVersionOriginalValue;
  7856. end;
  7857. if (shEncryptionUsed in SetupHeader.Options) and (CryptKey = '') then begin
  7858. LineNumber := SetupDirectiveLines[ssEncryption];
  7859. AbortCompileFmt(SCompilerEntryMissing2, ['Setup', 'Password']);
  7860. end;
  7861. if (SetupDirectiveLines[ssSignedUninstaller] = 0) and (SignTools.Count > 0) then
  7862. Include(SetupHeader.Options, shSignedUninstaller);
  7863. if not UseSetupLdr and
  7864. ((SignTools.Count > 0) or (shSignedUninstaller in SetupHeader.Options)) then
  7865. AbortCompile(SCompilerNoSetupLdrSignError);
  7866. LineNumber := SetupDirectiveLines[ssCreateUninstallRegKey];
  7867. CheckCheckOrInstall('CreateUninstallRegKey', SetupHeader.CreateUninstallRegKey, cikDirectiveCheck);
  7868. LineNumber := SetupDirectiveLines[ssUninstallable];
  7869. CheckCheckOrInstall('Uninstallable', SetupHeader.Uninstallable, cikDirectiveCheck);
  7870. LineNumber := SetupDirectiveLines[ssChangesEnvironment];
  7871. CheckCheckOrInstall('ChangesEnvironment', SetupHeader.ChangesEnvironment, cikDirectiveCheck);
  7872. LineNumber := SetupDirectiveLines[ssChangesAssociations];
  7873. CheckCheckOrInstall('ChangesAssociations', SetupHeader.ChangesAssociations, cikDirectiveCheck);
  7874. if Output and (OutputDir = '') then begin
  7875. LineNumber := SetupDirectiveLines[ssOutput];
  7876. AbortCompileOnLineFmt(SCompilerEntryInvalid2, ['Setup', 'OutputDir']);
  7877. end;
  7878. if (Output and (OutputBaseFileName = '')) or (PathLastDelimiter(BadFileNameChars + '\', OutputBaseFileName) <> 0) then begin
  7879. LineNumber := SetupDirectiveLines[ssOutputBaseFileName];
  7880. AbortCompileOnLineFmt(SCompilerEntryInvalid2, ['Setup', 'OutputBaseFileName']);
  7881. end else if OutputBaseFileName = 'setup' then { Warn even if Output is False }
  7882. WarningsList.Add(SCompilerOutputBaseFileNameSetup);
  7883. if (SetupDirectiveLines[ssOutputManifestFile] <> 0) and
  7884. ((Output and (OutputManifestFile = '')) or (PathLastDelimiter(BadFilePathChars, OutputManifestFile) <> 0)) then begin
  7885. LineNumber := SetupDirectiveLines[ssOutputManifestFile];
  7886. AbortCompileOnLineFmt(SCompilerEntryInvalid2, ['Setup', 'OutputManifestFile']);
  7887. end;
  7888. if shAlwaysUsePersonalGroup in SetupHeader.Options then
  7889. UsedUserAreas.Add('AlwaysUsePersonalGroup');
  7890. if SetupDirectiveLines[ssWizardSizePercent] = 0 then begin
  7891. if SetupHeader.WizardStyle = wsModern then
  7892. SetupHeader.WizardSizePercentX := 120
  7893. else
  7894. SetupHeader.WizardSizePercentX := 100;
  7895. SetupHeader.WizardSizePercentY := SetupHeader.WizardSizePercentX;
  7896. end;
  7897. if (SetupDirectiveLines[ssWizardResizable] = 0) and (SetupHeader.WizardStyle = wsModern) then
  7898. Include(SetupHeader.Options, shWizardResizable);
  7899. if (SetupHeader.MinVersion.NTVersion shr 16 = $0601) and (SetupHeader.MinVersion.NTServicePack < $100) then
  7900. WarningsList.Add(Format(SCompilerMinVersionRecommendation, ['6.1', '6.1sp1']));
  7901. LineNumber := 0;
  7902. SourceDir := AddBackslash(PathExpand(SourceDir));
  7903. if not FixedOutputDir then
  7904. OutputDir := PrependSourceDirName(OutputDir);
  7905. OutputDir := RemoveBackslashUnlessRoot(PathExpand(OutputDir));
  7906. LineNumber := SetupDirectiveLines[ssOutputDir];
  7907. if not DirExists(OutputDir) then begin
  7908. AddStatus(Format(SCompilerStatusCreatingOutputDir, [OutputDir]));
  7909. MkDirs(OutputDir);
  7910. end;
  7911. LineNumber := 0;
  7912. OutputDir := AddBackslash(OutputDir);
  7913. if SignedUninstallerDir = '' then
  7914. SignedUninstallerDir := OutputDir
  7915. else begin
  7916. SignedUninstallerDir := RemoveBackslashUnlessRoot(PathExpand(PrependSourceDirName(SignedUninstallerDir)));
  7917. if not DirExists(SignedUninstallerDir) then begin
  7918. AddStatus(Format(SCompilerStatusCreatingSignedUninstallerDir, [SignedUninstallerDir]));
  7919. MkDirs(SignedUninstallerDir);
  7920. end;
  7921. SignedUninstallerDir := AddBackslash(SignedUninstallerDir);
  7922. end;
  7923. { Read text files }
  7924. if LicenseFile <> '' then begin
  7925. LineNumber := SetupDirectiveLines[ssLicenseFile];
  7926. AddStatus(Format(SCompilerStatusReadingFile, ['LicenseFile']));
  7927. ReadTextFile(PrependSourceDirName(LicenseFile), -1, LicenseText);
  7928. end;
  7929. if InfoBeforeFile <> '' then begin
  7930. LineNumber := SetupDirectiveLines[ssInfoBeforeFile];
  7931. AddStatus(Format(SCompilerStatusReadingFile, ['InfoBeforeFile']));
  7932. ReadTextFile(PrependSourceDirName(InfoBeforeFile), -1, InfoBeforeText);
  7933. end;
  7934. if InfoAfterFile <> '' then begin
  7935. LineNumber := SetupDirectiveLines[ssInfoAfterFile];
  7936. AddStatus(Format(SCompilerStatusReadingFile, ['InfoAfterFile']));
  7937. ReadTextFile(PrependSourceDirName(InfoAfterFile), -1, InfoAfterText);
  7938. end;
  7939. LineNumber := 0;
  7940. CallIdleProc;
  7941. { Read wizard image }
  7942. LineNumber := SetupDirectiveLines[ssWizardImageFile];
  7943. AddStatus(Format(SCompilerStatusReadingFile, ['WizardImageFile']));
  7944. if WizardImageFile <> '' then begin
  7945. if SameText(WizardImageFile, 'compiler:WizModernImage.bmp') then begin
  7946. WarningsList.Add(Format(SCompilerWizImageRenamed, [WizardImageFile, 'compiler:WizClassicImage.bmp']));
  7947. WizardImageFile := 'compiler:WizClassicImage.bmp';
  7948. end;
  7949. WizardImages := CreateMemoryStreamsFromFiles('WizardImageFile', WizardImageFile)
  7950. end else
  7951. WizardImages := CreateMemoryStreamsFromResources(['WizardImage'], ['100', '150']);
  7952. LineNumber := SetupDirectiveLines[ssWizardSmallImageFile];
  7953. AddStatus(Format(SCompilerStatusReadingFile, ['WizardSmallImageFile']));
  7954. if WizardSmallImageFile <> '' then begin
  7955. if SameText(WizardSmallImageFile, 'compiler:WizModernSmallImage.bmp') then begin
  7956. WarningsList.Add(Format(SCompilerWizImageRenamed, [WizardSmallImageFile, 'compiler:WizClassicSmallImage.bmp']));
  7957. WizardSmallImageFile := 'compiler:WizClassicSmallImage.bmp';
  7958. end;
  7959. WizardSmallImages := CreateMemoryStreamsFromFiles('WizardSmallImage', WizardSmallImageFile)
  7960. end else
  7961. WizardSmallImages := CreateMemoryStreamsFromResources(['WizardSmallImage'], ['100', '125', '150', '175', '200', '225', '250']);
  7962. LineNumber := 0;
  7963. { Prepare Setup executable & signed uninstaller data }
  7964. if Output then begin
  7965. AddStatus(SCompilerStatusPreparingSetupExe);
  7966. PrepareSetupE32(SetupE32);
  7967. end else
  7968. AddStatus(SCompilerStatusSkippingPreparingSetupExe);
  7969. { Read languages:
  7970. 0. Determine final code pages:
  7971. Unicode Setup uses Unicode text and does not depend on the system code page. To
  7972. provide Setup with Unicode text without requiring Unicode .isl files (but still
  7973. supporting Unicode .iss, license and info files), the compiler converts the .isl
  7974. files to Unicode during compilation. It also does this if it finds ANSI plain text
  7975. license and info files. To be able to do this it needs to know the language's code
  7976. page but as seen above it can't simply take this from the current .isl. And license
  7977. and info files do not even have a language code page setting.
  7978. This means the Unicode compiler has to do an extra phase: following the logic above
  7979. it first determines the final language code page for each language, storing these
  7980. into an extra list called PreDataList, and then it continues as normal while using
  7981. the final language code page for any conversions needed.
  7982. Note: it must avoid caching the .isl files while determining the code pages, since
  7983. the conversion is done *before* the caching.
  7984. 1. Read Default.isl messages:
  7985. ReadDefaultMessages calls EnumMessages for Default.isl's [Messages], with Ext set to -2.
  7986. These messages are stored in DefaultLangData to be used as defaults for missing messages
  7987. later on. EnumLangOptions isn't called, the defaults will (at run-time) be displayed
  7988. using the code page of the language with the missing messages. EnumMessages for
  7989. Default.isl's [CustomMessages] also isn't called at this point, missing custom messages
  7990. are handled differently.
  7991. 2. Read [Languages] section and the .isl files the entries reference:
  7992. EnumLanguages is called for the script. For each [Languages] entry its parameters
  7993. are read and for the MessagesFiles parameter ReadMessagesFromFiles is called. For
  7994. each file ReadMessagesFromFiles first calls EnumLangOptions, then EnumMessages for
  7995. [Messages], and finally another EnumMessages for [CustomMessages], all with Ext set
  7996. to the index of the language.
  7997. All the [LangOptions] and [Messages] data is stored in single structures per language,
  7998. namely LanguageEntries[Ext] (langoptions) and LangDataList[Ext] (messages), any 'double'
  7999. directives or messages overwrite each other. This means if that for example the first
  8000. messages file does not specify a code page, but the second does, the language will
  8001. automatically use the code page of the second file. And vice versa.
  8002. The [CustomMessages] data is stored in a single list for all languages, with each
  8003. entry having a LangIndex property saying to which language it belongs. If a 'double'
  8004. custom message is found, the existing one is removed from the list.
  8005. 3. Read [LangOptions] & [Messages] & [CustomMessages] in the script:
  8006. ReadMessagesFromScript is called and this will first call CreateDefaultLanguageEntry
  8007. if no languages have been defined. CreateDefaultLanguageEntry first creates a language
  8008. with all settings set to the default, and then it calles ReadMessagesFromFiles for
  8009. Default.isl for this language. ReadMessagesFromFiles works as described above.
  8010. Note this is just like the script creator creating an entry for Default.isl.
  8011. ReadMessagesFromScript then first calls EnumLangOptions, then EnumMessages for
  8012. [Messages], and finally another EnumMessages for [CustomMessages] for the script.
  8013. Note this is just like ReadMessagesFromFiles does for files, except that Ext is set
  8014. to -1. This causes it to accept language identifiers ('en.LanguageCodePage=...'):
  8015. if the identifier is set the read data is stored only for that language in the
  8016. structures described above. If the identifier is not set, the read data is stored
  8017. for all languages either by writing to all structures (langoptions/messages) or by
  8018. adding an entry with LangIndex set to -1 (custommessages). This for example means
  8019. all language code pages read so far could be overwritten from the script.
  8020. ReadMessagesFromScript then checks for any missing messages and uses the messages
  8021. read in the very beginning to provide defaults.
  8022. After ReadMessagesFromScript returns, the read messages stored in the LangDataList
  8023. entries are streamed into the LanguageEntry.Data fields by PopulateLanguageEntryData.
  8024. 4. Check 'language completeness' of custom message constants:
  8025. CheckCustomMessageDefinitions is used to check for missing custom messages and
  8026. where necessary it 'promotes' a custom message by resetting its LangIndex property
  8027. to -1. }
  8028. { 0. Determine final language code pages }
  8029. AddStatus(SCompilerStatusDeterminingCodePages);
  8030. { 0.1. Read [Languages] section and [LangOptions] in the .isl files the
  8031. entries reference }
  8032. EnumIniSection(EnumLanguagesPreProc, 'Languages', 0, True, True, '', False, True);
  8033. CallIdleProc;
  8034. { 0.2. Read [LangOptions] in the script }
  8035. ReadMessagesFromScriptPre;
  8036. { 1. Read Default.isl messages }
  8037. AddStatus(SCompilerStatusReadingDefaultMessages);
  8038. ReadDefaultMessages;
  8039. { 2. Read [Languages] section and the .isl files the entries reference }
  8040. EnumIniSection(EnumLanguagesProc, 'Languages', 0, True, True, '', False, False);
  8041. CallIdleProc;
  8042. { 3. Read [LangOptions] & [Messages] & [CustomMessages] in the script }
  8043. AddStatus(SCompilerStatusParsingMessages);
  8044. ReadMessagesFromScript;
  8045. PopulateLanguageEntryData;
  8046. { 4. Check 'language completeness' of custom message constants }
  8047. CheckCustomMessageDefinitions;
  8048. { Read (but not compile) [Code] section }
  8049. ReadCode;
  8050. { Read [Types] section }
  8051. EnumIniSection(EnumTypesProc, 'Types', 0, True, True, '', False, False);
  8052. CallIdleProc;
  8053. { Read [Components] section }
  8054. EnumIniSection(EnumComponentsProc, 'Components', 0, True, True, '', False, False);
  8055. CallIdleProc;
  8056. { Read [Tasks] section }
  8057. EnumIniSection(EnumTasksProc, 'Tasks', 0, True, True, '', False, False);
  8058. CallIdleProc;
  8059. { Read [Dirs] section }
  8060. EnumIniSection(EnumDirsProc, 'Dirs', 0, True, True, '', False, False);
  8061. CallIdleProc;
  8062. { Read [Icons] section }
  8063. EnumIniSection(EnumIconsProc, 'Icons', 0, True, True, '', False, False);
  8064. CallIdleProc;
  8065. { Read [INI] section }
  8066. EnumIniSection(EnumINIProc, 'INI', 0, True, True, '', False, False);
  8067. CallIdleProc;
  8068. { Read [Registry] section }
  8069. EnumIniSection(EnumRegistryProc, 'Registry', 0, True, True, '', False, False);
  8070. CallIdleProc;
  8071. { Read [InstallDelete] section }
  8072. EnumIniSection(EnumDeleteProc, 'InstallDelete', 0, True, True, '', False, False);
  8073. CallIdleProc;
  8074. { Read [UninstallDelete] section }
  8075. EnumIniSection(EnumDeleteProc, 'UninstallDelete', 1, True, True, '', False, False);
  8076. CallIdleProc;
  8077. { Read [Run] section }
  8078. EnumIniSection(EnumRunProc, 'Run', 0, True, True, '', False, False);
  8079. CallIdleProc;
  8080. { Read [UninstallRun] section }
  8081. EnumIniSection(EnumRunProc, 'UninstallRun', 1, True, True, '', False, False);
  8082. CallIdleProc;
  8083. if MissingRunOnceIdsWarning and MissingRunOnceIds then
  8084. WarningsList.Add(Format(SCompilerMissingRunOnceIdsWarning, ['UninstallRun', 'RunOnceId']));
  8085. { Read [Files] section }
  8086. if not TryStrToBoolean(SetupHeader.Uninstallable, Uninstallable) or Uninstallable then
  8087. EnumFilesProc('', 1);
  8088. EnumIniSection(EnumFilesProc, 'Files', 0, True, True, '', False, False);
  8089. CallIdleProc;
  8090. if UsedUserAreasWarning and (UsedUserAreas.Count > 0) and
  8091. (SetupHeader.PrivilegesRequired in [prPowerUser, prAdmin]) then begin
  8092. if SetupHeader.PrivilegesRequired = prPowerUser then
  8093. PrivilegesRequiredValue := 'poweruser'
  8094. else
  8095. PrivilegesRequiredValue := 'admin';
  8096. WarningsList.Add(Format(SCompilerUsedUserAreasWarning, ['Setup',
  8097. 'PrivilegesRequired', PrivilegesRequiredValue, UsedUserAreas.CommaText]));
  8098. end;
  8099. { Read decompressor DLL. Must be done after [Files] is parsed, since
  8100. SetupHeader.CompressMethod isn't set until then }
  8101. case SetupHeader.CompressMethod of
  8102. cmZip: begin
  8103. AddStatus(Format(SCompilerStatusReadingFile, ['isunzlib.dll']));
  8104. DecompressorDLL := CreateMemoryStreamFromFile(CompilerDir + 'isunzlib.dll');
  8105. end;
  8106. cmBzip: begin
  8107. AddStatus(Format(SCompilerStatusReadingFile, ['isbunzip.dll']));
  8108. DecompressorDLL := CreateMemoryStreamFromFile(CompilerDir + 'isbunzip.dll');
  8109. end;
  8110. end;
  8111. { Read decryption DLL }
  8112. if shEncryptionUsed in SetupHeader.Options then begin
  8113. AddStatus(Format(SCompilerStatusReadingFile, ['iscrypt.dll']));
  8114. if not NewFileExists(CompilerDir + 'iscrypt.dll') then
  8115. AbortCompile(SCompilerISCryptMissing);
  8116. DecryptionDLL := CreateMemoryStreamFromFile(CompilerDir + 'iscrypt.dll');
  8117. end;
  8118. { Add default types if necessary }
  8119. if (ComponentEntries.Count > 0) and (TypeEntries.Count = 0) then begin
  8120. AddDefaultSetupType(DefaultTypeEntryNames[0], [], ttDefaultFull);
  8121. AddDefaultSetupType(DefaultTypeEntryNames[1], [], ttDefaultCompact);
  8122. AddDefaultSetupType(DefaultTypeEntryNames[2], [toIsCustom], ttDefaultCustom);
  8123. end;
  8124. { Check existence of expected custom message constants }
  8125. CheckCustomMessageReferences;
  8126. { Compile CodeText }
  8127. CompileCode;
  8128. CallIdleProc;
  8129. { Clear any existing setup* files out of the output directory first (even
  8130. if output is disabled. }
  8131. EmptyOutputDir(True);
  8132. if OutputManifestFile <> '' then
  8133. DeleteFile(PrependDirName(OutputManifestFile, OutputDir));
  8134. { Create setup files }
  8135. if Output then begin
  8136. AddStatus(SCompilerStatusCreateSetupFiles);
  8137. ExeFilename := OutputDir + OutputBaseFilename + '.exe';
  8138. try
  8139. if not UseSetupLdr then begin
  8140. SetupFile := TFile.Create(ExeFilename, fdCreateAlways, faWrite, fsNone);
  8141. try
  8142. SetupFile.WriteBuffer(SetupE32.Memory^, SetupE32.Size.Lo);
  8143. SizeOfExe := SetupFile.Size.Lo;
  8144. finally
  8145. SetupFile.Free;
  8146. end;
  8147. CallIdleProc;
  8148. if not DiskSpanning then begin
  8149. { Create SETUP-0.BIN and SETUP-1.BIN }
  8150. CompressFiles('', 0);
  8151. CreateSetup0File;
  8152. end
  8153. else begin
  8154. { Create SETUP-0.BIN and SETUP-*.BIN }
  8155. SizeOfHeaders := CreateSetup0File;
  8156. CompressFiles('', RoundToNearestClusterSize(SizeOfExe) +
  8157. RoundToNearestClusterSize(SizeOfHeaders) +
  8158. RoundToNearestClusterSize(ReserveBytes));
  8159. { CompressFiles modifies setup header data, so go back and
  8160. rewrite it }
  8161. if CreateSetup0File <> SizeOfHeaders then
  8162. { Make sure new and old size match. No reason why they
  8163. shouldn't but check just in case }
  8164. AbortCompile(SCompilerSetup0Mismatch);
  8165. end;
  8166. end
  8167. else begin
  8168. CopyFileOrAbort(CompilerDir + 'SETUPLDR.E32', ExeFilename);
  8169. { if there was a read-only attribute, remove it }
  8170. SetFileAttributes(PChar(ExeFilename), FILE_ATTRIBUTE_ARCHIVE);
  8171. if SetupIconFilename <> '' then begin
  8172. { update icons }
  8173. AddStatus(Format(SCompilerStatusUpdatingIcons, ['SETUP.EXE']));
  8174. LineNumber := SetupDirectiveLines[ssSetupIconFile];
  8175. UpdateIcons(ExeFilename, PrependSourceDirName(SetupIconFilename), False);
  8176. LineNumber := 0;
  8177. end;
  8178. SetupFile := TFile.Create(ExeFilename, fdOpenExisting, faReadWrite, fsNone);
  8179. try
  8180. UpdateSetupPEHeaderFields(SetupFile, TerminalServicesAware, DEPCompatible, ASLRCompatible);
  8181. SizeOfExe := SetupFile.Size.Lo;
  8182. finally
  8183. SetupFile.Free;
  8184. end;
  8185. CallIdleProc;
  8186. { When disk spanning isn't used, place the compressed files inside
  8187. SETUP.EXE }
  8188. if not DiskSpanning then
  8189. CompressFiles(ExeFilename, 0);
  8190. ExeFile := TFile.Create(ExeFilename, fdOpenExisting, faReadWrite, fsNone);
  8191. try
  8192. ExeFile.SeekToEnd;
  8193. { Move the data from SETUP.E?? into the SETUP.EXE, and write
  8194. header data }
  8195. FillChar(SetupLdrOffsetTable, SizeOf(SetupLdrOffsetTable), 0);
  8196. SetupLdrOffsetTable.ID := SetupLdrOffsetTableID;
  8197. SetupLdrOffsetTable.Version := SetupLdrOffsetTableVersion;
  8198. SetupLdrOffsetTable.Offset0 := ExeFile.Position.Lo;
  8199. SizeOfHeaders := WriteSetup0(ExeFile);
  8200. SetupLdrOffsetTable.OffsetEXE := ExeFile.Position.Lo;
  8201. CompressSetupE32(SetupE32, ExeFile, SetupLdrOffsetTable.UncompressedSizeEXE,
  8202. SetupLdrOffsetTable.CRCEXE);
  8203. SetupLdrOffsetTable.TotalSize := ExeFile.Size.Lo;
  8204. if DiskSpanning then begin
  8205. SetupLdrOffsetTable.Offset1 := 0;
  8206. { Compress the files in SETUP-*.BIN after we know the size of
  8207. SETUP.EXE }
  8208. CompressFiles('',
  8209. RoundToNearestClusterSize(SetupLdrOffsetTable.TotalSize) +
  8210. RoundToNearestClusterSize(ReserveBytes));
  8211. { CompressFiles modifies setup header data, so go back and
  8212. rewrite it }
  8213. ExeFile.Seek(SetupLdrOffsetTable.Offset0);
  8214. if WriteSetup0(ExeFile) <> SizeOfHeaders then
  8215. { Make sure new and old size match. No reason why they
  8216. shouldn't but check just in case }
  8217. AbortCompile(SCompilerSetup0Mismatch);
  8218. end
  8219. else
  8220. SetupLdrOffsetTable.Offset1 := SizeOfExe;
  8221. SetupLdrOffsetTable.TableCRC := GetCRC32(SetupLdrOffsetTable,
  8222. SizeOf(SetupLdrOffsetTable) - SizeOf(SetupLdrOffsetTable.TableCRC));
  8223. { Write SetupLdrOffsetTable to SETUP.EXE }
  8224. if SeekToResourceData(ExeFile, Cardinal(RT_RCDATA), SetupLdrOffsetTableResID) <> SizeOf(SetupLdrOffsetTable) then
  8225. AbortCompile('Wrong offset table resource size');
  8226. ExeFile.WriteBuffer(SetupLdrOffsetTable, SizeOf(SetupLdrOffsetTable));
  8227. { Update version info }
  8228. AddStatus(Format(SCompilerStatusUpdatingVersionInfo, ['SETUP.EXE']));
  8229. UpdateVersionInfo(ExeFile, VersionInfoVersion, VersionInfoProductVersion, VersionInfoCompany,
  8230. VersionInfoDescription, VersionInfoTextVersion,
  8231. VersionInfoCopyright, VersionInfoProductName, VersionInfoProductTextVersion, VersionInfoOriginalFileName,
  8232. True);
  8233. { Update manifest if needed }
  8234. if UseSetupLdr then begin
  8235. AddStatus(Format(SCompilerStatusUpdatingManifest, ['SETUP.EXE']));
  8236. CompExeUpdate.PreventCOMCTL32Sideloading(ExeFile);
  8237. end;
  8238. { For some reason, on Win95 the date/time of the EXE sometimes
  8239. doesn't get updated after it's been written to so it has to
  8240. manually set it. (I don't get it!!) }
  8241. UpdateTimeStamp(ExeFile.Handle);
  8242. finally
  8243. ExeFile.Free;
  8244. end;
  8245. end;
  8246. { Sign }
  8247. if SignTools.Count > 0 then begin
  8248. AddStatus(SCompilerStatusSigningSetup);
  8249. Sign(ExeFileName);
  8250. end;
  8251. except
  8252. EmptyOutputDir(False);
  8253. raise;
  8254. end;
  8255. CallIdleProc;
  8256. { Create manifest file }
  8257. if OutputManifestFile <> '' then begin
  8258. AddStatus(SCompilerStatusCreateManifestFile);
  8259. CreateManifestFile;
  8260. CallIdleProc;
  8261. end;
  8262. end else begin
  8263. AddStatus(SCompilerStatusSkippingCreateSetupFiles);
  8264. ExeFilename := '';
  8265. end;
  8266. { Finalize debug info }
  8267. FinalizeDebugInfo;
  8268. { Done }
  8269. AddStatus('');
  8270. for I := 0 to WarningsList.Count-1 do
  8271. AddStatus(SCompilerStatusWarning + WarningsList[I], True);
  8272. asm jmp @1; db 0,'Inno Setup Compiler, Copyright (C) 1997-2024 Jordan Russell, '
  8273. db 'Portions Copyright (C) 2000-2024 Martijn Laan',0; @1: end;
  8274. { Note: Removing or modifying the copyright text is a violation of the
  8275. Inno Setup license agreement; see LICENSE.TXT. }
  8276. finally
  8277. CallPreprocessorCleanupProc;
  8278. UsedUserAreas.Clear;
  8279. WarningsList.Clear;
  8280. { Free all the data }
  8281. DecryptionDLL.Free;
  8282. DecompressorDLL.Free;
  8283. SetupE32.Free;
  8284. WizardSmallImages.Free;
  8285. WizardImages.Free;
  8286. FreeListItems(LanguageEntries, SetupLanguageEntryStrings, SetupLanguageEntryAnsiStrings);
  8287. FreeListItems(CustomMessageEntries, SetupCustomMessageEntryStrings, SetupCustomMessageEntryAnsiStrings);
  8288. FreeListItems(PermissionEntries, SetupPermissionEntryStrings, SetupPermissionEntryAnsiStrings);
  8289. FreeListItems(TypeEntries, SetupTypeEntryStrings, SetupTypeEntryAnsiStrings);
  8290. FreeListItems(ComponentEntries, SetupComponentEntryStrings, SetupComponentEntryAnsiStrings);
  8291. FreeListItems(TaskEntries, SetupTaskEntryStrings, SetupTaskEntryAnsiStrings);
  8292. FreeListItems(DirEntries, SetupDirEntryStrings, SetupDirEntryAnsiStrings);
  8293. FreeListItems(FileEntries, SetupFileEntryStrings, SetupFileEntryAnsiStrings);
  8294. FreeListItems(FileLocationEntries, SetupFileLocationEntryStrings, SetupFileLocationEntryAnsiStrings);
  8295. FreeListItems(IconEntries, SetupIconEntryStrings, SetupIconEntryAnsiStrings);
  8296. FreeListItems(IniEntries, SetupIniEntryStrings, SetupIniEntryAnsiStrings);
  8297. FreeListItems(RegistryEntries, SetupRegistryEntryStrings, SetupRegistryEntryAnsiStrings);
  8298. FreeListItems(InstallDeleteEntries, SetupDeleteEntryStrings, SetupDeleteEntryAnsiStrings);
  8299. FreeListItems(UninstallDeleteEntries, SetupDeleteEntryStrings, SetupDeleteEntryAnsiStrings);
  8300. FreeListItems(RunEntries, SetupRunEntryStrings, SetupRunEntryAnsiStrings);
  8301. FreeListItems(UninstallRunEntries, SetupRunEntryStrings, SetupRunEntryAnsiStrings);
  8302. FileLocationEntryFilenames.Clear;
  8303. FreeLineInfoList(ExpectedCustomMessageNames);
  8304. FreeLangData;
  8305. FreePreLangData;
  8306. FreeScriptFiles;
  8307. FreeLineInfoList(CodeText);
  8308. FreeAndNil(CompressProps);
  8309. FreeAndNil(InternalCompressProps);
  8310. end;
  8311. end;
  8312. { Interface functions }
  8313. function ISCompileScript(const Params: TCompileScriptParamsEx;
  8314. const PropagateExceptions: Boolean): Integer;
  8315. function CheckParams(const Params: TCompileScriptParamsEx): Boolean;
  8316. begin
  8317. Result := ((Params.Size = SizeOf(Params)) or
  8318. (Params.Size = SizeOf(TCompileScriptParams))) and
  8319. Assigned(Params.CallbackProc);
  8320. end;
  8321. procedure InitializeSetupCompiler(const SetupCompiler: TSetupCompiler;
  8322. const Params: TCompileScriptParamsEx);
  8323. begin
  8324. SetupCompiler.AppData := Params.AppData;
  8325. SetupCompiler.CallbackProc := Params.CallbackProc;
  8326. if Assigned(Params.CompilerPath) then
  8327. SetupCompiler.CompilerDir := Params.CompilerPath
  8328. else
  8329. SetupCompiler.CompilerDir := PathExtractPath(GetSelfFilename);
  8330. SetupCompiler.SourceDir := Params.SourcePath;
  8331. end;
  8332. function EncodeIncludedFilenames(const IncludedFilenames: TStringList): String;
  8333. var
  8334. S: String;
  8335. I: Integer;
  8336. begin
  8337. S := '';
  8338. for I := 0 to IncludedFilenames.Count-1 do
  8339. S := S + IncludedFilenames[I] + #0;
  8340. Result := S;
  8341. end;
  8342. procedure NotifyPreproc(const SetupCompiler: TSetupCompiler);
  8343. var
  8344. Data: TCompilerCallbackData;
  8345. S: String;
  8346. begin
  8347. Data.PreprocessedScript := PChar(SetupCompiler.PreprocOutput);
  8348. S := EncodeIncludedFilenames(SetupCompiler.PreprocIncludedFilenames);
  8349. Data.IncludedFilenames := PChar(S);
  8350. Params.CallbackProc(iscbNotifyPreproc, Data, Params.AppData);
  8351. end;
  8352. procedure NotifySuccess(const SetupCompiler: TSetupCompiler);
  8353. var
  8354. Data: TCompilerCallbackData;
  8355. begin
  8356. Data.OutputExeFilename := PChar(SetupCompiler.ExeFilename);
  8357. Data.DebugInfo := SetupCompiler.DebugInfo.Memory;
  8358. Data.DebugInfoSize := SetupCompiler.DebugInfo.Size;
  8359. Params.CallbackProc(iscbNotifySuccess, Data, Params.AppData);
  8360. end;
  8361. procedure NotifyError(const SetupCompiler: TSetupCompiler);
  8362. var
  8363. Data: TCompilerCallbackData;
  8364. S: String;
  8365. begin
  8366. Data.ErrorMsg := nil;
  8367. Data.ErrorFilename := nil;
  8368. Data.ErrorLine := 0;
  8369. if not(ExceptObject is EAbort) then begin
  8370. S := GetExceptMessage;
  8371. Data.ErrorMsg := PChar(S);
  8372. { use a Pointer cast instead of PChar so that we'll get a null
  8373. pointer if the string is empty }
  8374. Data.ErrorFilename := Pointer(SetupCompiler.LineFilename);
  8375. Data.ErrorLine := SetupCompiler.LineNumber;
  8376. end;
  8377. Params.CallbackProc(iscbNotifyError, Data, Params.AppData);
  8378. end;
  8379. var
  8380. SetupCompiler: TSetupCompiler;
  8381. P: PChar;
  8382. P2: Integer;
  8383. begin
  8384. if not CheckParams(Params) then begin
  8385. Result := isceInvalidParam;
  8386. Exit;
  8387. end;
  8388. SetupCompiler := TSetupCompiler.Create(nil);
  8389. try
  8390. InitializeSetupCompiler(SetupCompiler, Params);
  8391. { Parse Options (only present in TCompileScriptParamsEx) }
  8392. if (Params.Size <> SizeOf(TCompileScriptParams)) and Assigned(Params.Options) then begin
  8393. P := Params.Options;
  8394. while P^ <> #0 do begin
  8395. if StrLIComp(P, 'Output=', Length('Output=')) = 0 then begin
  8396. Inc(P, Length('Output='));
  8397. if TryStrToBoolean(P, SetupCompiler.Output) then
  8398. SetupCompiler.FixedOutput := True
  8399. else begin
  8400. { Bad option }
  8401. Result := isceInvalidParam;
  8402. Exit;
  8403. end;
  8404. end
  8405. else if StrLIComp(P, 'OutputDir=', Length('OutputDir=')) = 0 then begin
  8406. Inc(P, Length('OutputDir='));
  8407. SetupCompiler.OutputDir := P;
  8408. SetupCompiler.FixedOutputDir := True;
  8409. end
  8410. else if StrLIComp(P, 'OutputBaseFilename=', Length('OutputBaseFilename=')) = 0 then begin
  8411. Inc(P, Length('OutputBaseFilename='));
  8412. SetupCompiler.OutputBaseFilename := P;
  8413. SetupCompiler.FixedOutputBaseFilename := True;
  8414. end
  8415. else if StrLIComp(P, 'SignTool-', Length('SignTool-')) = 0 then begin
  8416. Inc(P, Length('SignTool-'));
  8417. P2 := Pos('=', P);
  8418. if (P2 <> 0) then
  8419. SetupCompiler.AddSignTool(Copy(P, 1, P2-1), Copy(P, P2+1, MaxInt))
  8420. else begin
  8421. { Bad option }
  8422. Result := isceInvalidParam;
  8423. Exit;
  8424. end;
  8425. end
  8426. else if StrLIComp(P, 'ISPP:', Length('ISPP:')) = 0 then begin
  8427. SetupCompiler.PreprocOptionsString :=
  8428. SetupCompiler.PreprocOptionsString + P + #0;
  8429. end
  8430. else begin
  8431. { Unknown option }
  8432. Result := isceInvalidParam;
  8433. Exit;
  8434. end;
  8435. Inc(P, StrLen(P) + 1);
  8436. end;
  8437. end;
  8438. try
  8439. try
  8440. SetupCompiler.Compile;
  8441. finally
  8442. NotifyPreproc(SetupCompiler);
  8443. end;
  8444. Result := isceNoError;
  8445. NotifySuccess(SetupCompiler);
  8446. except
  8447. Result := isceCompileFailure;
  8448. NotifyError(SetupCompiler);
  8449. if PropagateExceptions then
  8450. raise;
  8451. end;
  8452. finally
  8453. SetupCompiler.Free;
  8454. end;
  8455. end;
  8456. function ISGetVersion: PCompilerVersionInfo;
  8457. const
  8458. Ver: TCompilerVersionInfo =
  8459. (Title: SetupTitle; Version: SetupVersion; BinVersion: SetupBinVersion);
  8460. begin
  8461. Result := @Ver;
  8462. end;
  8463. initialization
  8464. finalization
  8465. if CryptProv <> 0 then begin
  8466. CryptReleaseContext(CryptProv, 0);
  8467. CryptProv := 0;
  8468. end;
  8469. end.