Compiler.SetupCompiler.pas 302 KB

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