| 12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267226822692270227122722273227422752276227722782279228022812282228322842285228622872288228922902291229222932294229522962297229822992300230123022303230423052306230723082309231023112312231323142315231623172318231923202321232223232324232523262327232823292330233123322333233423352336233723382339234023412342234323442345234623472348234923502351235223532354235523562357235823592360236123622363236423652366236723682369237023712372237323742375237623772378237923802381238223832384238523862387238823892390239123922393239423952396239723982399240024012402240324042405240624072408240924102411241224132414241524162417241824192420242124222423242424252426242724282429243024312432243324342435243624372438243924402441244224432444244524462447244824492450245124522453245424552456245724582459246024612462246324642465246624672468246924702471247224732474247524762477247824792480248124822483248424852486248724882489249024912492249324942495249624972498249925002501250225032504250525062507250825092510251125122513251425152516251725182519252025212522252325242525252625272528252925302531253225332534253525362537253825392540254125422543254425452546254725482549255025512552255325542555255625572558255925602561256225632564256525662567256825692570257125722573257425752576257725782579258025812582258325842585258625872588258925902591259225932594259525962597259825992600260126022603260426052606260726082609261026112612261326142615261626172618261926202621262226232624262526262627262826292630263126322633263426352636263726382639264026412642264326442645264626472648264926502651265226532654265526562657265826592660266126622663266426652666266726682669267026712672267326742675267626772678267926802681268226832684268526862687268826892690269126922693269426952696269726982699270027012702270327042705270627072708270927102711271227132714271527162717271827192720272127222723272427252726272727282729273027312732273327342735273627372738273927402741274227432744274527462747274827492750275127522753275427552756275727582759276027612762276327642765276627672768276927702771277227732774277527762777277827792780278127822783278427852786278727882789279027912792279327942795279627972798279928002801280228032804280528062807280828092810281128122813281428152816281728182819282028212822282328242825282628272828282928302831283228332834283528362837283828392840284128422843284428452846284728482849285028512852285328542855285628572858285928602861286228632864286528662867286828692870287128722873287428752876287728782879288028812882288328842885288628872888288928902891289228932894289528962897289828992900290129022903290429052906290729082909291029112912291329142915291629172918291929202921292229232924292529262927292829292930293129322933293429352936293729382939294029412942294329442945294629472948294929502951295229532954295529562957295829592960296129622963296429652966296729682969297029712972297329742975297629772978297929802981298229832984298529862987298829892990299129922993299429952996299729982999300030013002300330043005300630073008300930103011301230133014301530163017301830193020302130223023302430253026302730283029303030313032303330343035303630373038303930403041304230433044304530463047304830493050305130523053305430553056305730583059306030613062306330643065306630673068306930703071307230733074307530763077307830793080308130823083308430853086308730883089309030913092309330943095309630973098309931003101310231033104310531063107310831093110311131123113311431153116311731183119312031213122312331243125312631273128312931303131313231333134313531363137313831393140314131423143314431453146314731483149315031513152315331543155315631573158315931603161316231633164316531663167316831693170317131723173317431753176317731783179318031813182318331843185318631873188318931903191319231933194319531963197319831993200320132023203320432053206320732083209321032113212321332143215321632173218321932203221322232233224322532263227322832293230323132323233323432353236323732383239324032413242324332443245324632473248324932503251325232533254325532563257325832593260326132623263326432653266326732683269327032713272327332743275327632773278327932803281328232833284328532863287328832893290329132923293329432953296329732983299330033013302330333043305330633073308330933103311331233133314331533163317331833193320332133223323332433253326332733283329333033313332333333343335333633373338333933403341334233433344334533463347334833493350335133523353335433553356335733583359336033613362336333643365336633673368336933703371337233733374337533763377337833793380338133823383338433853386338733883389339033913392339333943395339633973398339934003401340234033404340534063407340834093410341134123413341434153416341734183419342034213422342334243425342634273428342934303431343234333434343534363437343834393440344134423443344434453446344734483449345034513452345334543455345634573458345934603461346234633464346534663467346834693470347134723473347434753476347734783479348034813482348334843485348634873488348934903491349234933494349534963497349834993500350135023503350435053506350735083509351035113512351335143515351635173518351935203521352235233524352535263527352835293530353135323533353435353536353735383539354035413542354335443545354635473548354935503551355235533554355535563557355835593560356135623563356435653566356735683569357035713572357335743575357635773578357935803581358235833584358535863587358835893590359135923593359435953596359735983599360036013602360336043605360636073608360936103611361236133614361536163617361836193620362136223623362436253626362736283629363036313632363336343635363636373638363936403641364236433644364536463647364836493650365136523653365436553656365736583659366036613662366336643665366636673668366936703671367236733674367536763677367836793680368136823683368436853686368736883689369036913692369336943695369636973698369937003701370237033704370537063707370837093710371137123713371437153716371737183719372037213722372337243725372637273728372937303731373237333734373537363737373837393740374137423743374437453746374737483749375037513752375337543755375637573758375937603761376237633764376537663767376837693770377137723773377437753776377737783779378037813782378337843785378637873788378937903791379237933794379537963797379837993800380138023803380438053806380738083809381038113812381338143815381638173818381938203821382238233824382538263827382838293830383138323833383438353836383738383839384038413842384338443845384638473848384938503851385238533854385538563857385838593860386138623863386438653866386738683869387038713872387338743875387638773878387938803881388238833884388538863887388838893890389138923893389438953896389738983899390039013902390339043905390639073908390939103911391239133914391539163917391839193920392139223923392439253926392739283929393039313932393339343935393639373938393939403941394239433944394539463947394839493950395139523953395439553956395739583959396039613962396339643965396639673968396939703971397239733974397539763977397839793980398139823983398439853986398739883989399039913992399339943995399639973998399940004001400240034004400540064007400840094010401140124013401440154016401740184019402040214022402340244025402640274028402940304031403240334034403540364037403840394040404140424043404440454046404740484049405040514052405340544055405640574058405940604061406240634064406540664067406840694070407140724073407440754076407740784079408040814082408340844085408640874088408940904091409240934094409540964097409840994100410141024103410441054106410741084109411041114112411341144115411641174118411941204121412241234124412541264127412841294130413141324133413441354136413741384139414041414142414341444145414641474148414941504151415241534154415541564157415841594160416141624163416441654166416741684169417041714172417341744175417641774178417941804181418241834184418541864187418841894190419141924193419441954196419741984199420042014202420342044205420642074208420942104211421242134214421542164217421842194220422142224223422442254226422742284229423042314232423342344235423642374238423942404241424242434244424542464247424842494250425142524253425442554256425742584259426042614262426342644265426642674268426942704271427242734274427542764277427842794280428142824283428442854286428742884289429042914292429342944295429642974298429943004301430243034304430543064307430843094310431143124313431443154316431743184319432043214322432343244325432643274328432943304331433243334334433543364337433843394340434143424343434443454346434743484349435043514352435343544355435643574358435943604361436243634364436543664367436843694370437143724373437443754376437743784379438043814382438343844385438643874388438943904391439243934394439543964397439843994400440144024403440444054406440744084409441044114412441344144415441644174418441944204421442244234424442544264427442844294430443144324433443444354436443744384439444044414442444344444445444644474448444944504451445244534454445544564457445844594460446144624463446444654466446744684469447044714472447344744475447644774478447944804481448244834484448544864487448844894490449144924493449444954496449744984499450045014502450345044505450645074508450945104511451245134514451545164517451845194520452145224523452445254526452745284529453045314532453345344535453645374538453945404541454245434544454545464547454845494550455145524553455445554556455745584559456045614562456345644565456645674568456945704571457245734574457545764577457845794580458145824583458445854586458745884589459045914592459345944595459645974598459946004601460246034604460546064607460846094610461146124613461446154616461746184619462046214622462346244625462646274628462946304631463246334634463546364637463846394640464146424643464446454646464746484649465046514652465346544655465646574658465946604661466246634664466546664667466846694670467146724673467446754676467746784679468046814682468346844685468646874688468946904691469246934694469546964697469846994700470147024703470447054706470747084709471047114712471347144715471647174718471947204721472247234724472547264727472847294730473147324733473447354736473747384739474047414742474347444745474647474748474947504751475247534754475547564757475847594760476147624763476447654766476747684769477047714772477347744775477647774778477947804781478247834784478547864787478847894790479147924793479447954796479747984799480048014802480348044805480648074808480948104811481248134814481548164817481848194820482148224823482448254826482748284829483048314832483348344835483648374838483948404841484248434844484548464847484848494850485148524853485448554856485748584859486048614862486348644865486648674868486948704871487248734874487548764877487848794880488148824883488448854886488748884889489048914892489348944895489648974898489949004901490249034904490549064907490849094910491149124913491449154916491749184919492049214922492349244925492649274928492949304931493249334934493549364937493849394940494149424943494449454946494749484949495049514952495349544955495649574958495949604961496249634964496549664967496849694970497149724973497449754976497749784979498049814982498349844985498649874988498949904991499249934994499549964997499849995000500150025003500450055006500750085009501050115012501350145015501650175018501950205021502250235024502550265027502850295030503150325033503450355036503750385039504050415042504350445045504650475048504950505051505250535054505550565057505850595060506150625063506450655066506750685069507050715072507350745075507650775078507950805081508250835084508550865087508850895090509150925093509450955096509750985099510051015102510351045105510651075108510951105111511251135114511551165117511851195120512151225123512451255126512751285129513051315132513351345135513651375138513951405141514251435144514551465147514851495150515151525153515451555156515751585159516051615162516351645165516651675168516951705171517251735174517551765177517851795180518151825183518451855186518751885189519051915192519351945195519651975198519952005201520252035204520552065207520852095210521152125213521452155216521752185219522052215222522352245225522652275228522952305231523252335234523552365237523852395240524152425243524452455246524752485249525052515252525352545255525652575258525952605261526252635264526552665267526852695270527152725273527452755276527752785279528052815282528352845285528652875288528952905291529252935294529552965297529852995300530153025303530453055306530753085309531053115312531353145315531653175318531953205321532253235324532553265327532853295330533153325333533453355336533753385339534053415342534353445345534653475348534953505351535253535354535553565357535853595360536153625363536453655366536753685369537053715372537353745375537653775378537953805381538253835384538553865387538853895390539153925393539453955396539753985399540054015402540354045405540654075408540954105411541254135414541554165417541854195420542154225423542454255426542754285429543054315432543354345435543654375438543954405441544254435444544554465447544854495450545154525453545454555456545754585459546054615462546354645465546654675468546954705471547254735474547554765477547854795480548154825483548454855486548754885489549054915492549354945495549654975498549955005501550255035504550555065507550855095510551155125513551455155516551755185519552055215522552355245525552655275528552955305531553255335534553555365537553855395540554155425543554455455546554755485549555055515552555355545555555655575558555955605561556255635564556555665567556855695570557155725573557455755576557755785579558055815582558355845585558655875588558955905591559255935594559555965597559855995600560156025603560456055606560756085609561056115612561356145615561656175618561956205621562256235624562556265627562856295630563156325633563456355636563756385639564056415642564356445645564656475648564956505651565256535654565556565657565856595660566156625663566456655666566756685669567056715672567356745675567656775678567956805681568256835684568556865687568856895690569156925693569456955696569756985699570057015702570357045705570657075708570957105711571257135714571557165717571857195720572157225723572457255726572757285729573057315732573357345735573657375738573957405741574257435744574557465747574857495750575157525753575457555756575757585759576057615762576357645765576657675768576957705771577257735774577557765777577857795780578157825783578457855786578757885789579057915792579357945795579657975798579958005801580258035804580558065807580858095810581158125813581458155816581758185819582058215822582358245825582658275828582958305831583258335834583558365837583858395840584158425843584458455846584758485849585058515852585358545855585658575858585958605861586258635864586558665867586858695870587158725873587458755876587758785879588058815882588358845885588658875888588958905891589258935894589558965897589858995900590159025903590459055906590759085909591059115912591359145915591659175918591959205921592259235924592559265927592859295930593159325933593459355936593759385939594059415942594359445945594659475948594959505951595259535954595559565957595859595960596159625963596459655966596759685969597059715972597359745975597659775978597959805981598259835984598559865987598859895990599159925993599459955996599759985999600060016002600360046005600660076008600960106011601260136014601560166017601860196020602160226023602460256026602760286029603060316032603360346035603660376038603960406041604260436044604560466047604860496050605160526053605460556056605760586059606060616062606360646065606660676068606960706071607260736074607560766077607860796080608160826083608460856086608760886089609060916092609360946095609660976098609961006101610261036104610561066107610861096110611161126113611461156116611761186119612061216122612361246125612661276128612961306131613261336134613561366137613861396140614161426143614461456146614761486149615061516152615361546155615661576158615961606161616261636164616561666167616861696170617161726173617461756176617761786179618061816182618361846185618661876188618961906191619261936194619561966197619861996200620162026203620462056206620762086209621062116212621362146215621662176218621962206221622262236224622562266227622862296230623162326233623462356236623762386239624062416242624362446245624662476248624962506251625262536254625562566257625862596260626162626263626462656266626762686269627062716272627362746275627662776278627962806281628262836284628562866287628862896290629162926293629462956296629762986299630063016302630363046305630663076308630963106311631263136314631563166317631863196320632163226323632463256326632763286329633063316332633363346335633663376338633963406341634263436344634563466347634863496350635163526353635463556356635763586359636063616362636363646365636663676368636963706371637263736374637563766377637863796380638163826383638463856386638763886389639063916392639363946395639663976398639964006401640264036404640564066407640864096410641164126413641464156416641764186419642064216422642364246425642664276428642964306431643264336434643564366437643864396440644164426443644464456446644764486449645064516452645364546455645664576458645964606461646264636464646564666467646864696470647164726473647464756476647764786479648064816482648364846485648664876488648964906491649264936494649564966497649864996500650165026503650465056506650765086509651065116512651365146515651665176518651965206521652265236524652565266527652865296530653165326533653465356536653765386539654065416542654365446545654665476548654965506551655265536554655565566557655865596560656165626563656465656566656765686569657065716572657365746575657665776578657965806581658265836584658565866587658865896590659165926593659465956596659765986599660066016602660366046605660666076608660966106611661266136614661566166617661866196620662166226623662466256626662766286629663066316632663366346635663666376638663966406641664266436644664566466647664866496650665166526653665466556656665766586659666066616662666366646665666666676668666966706671667266736674667566766677667866796680668166826683668466856686668766886689669066916692669366946695669666976698669967006701670267036704670567066707670867096710671167126713671467156716671767186719672067216722672367246725672667276728672967306731673267336734673567366737673867396740674167426743674467456746674767486749675067516752675367546755675667576758675967606761676267636764676567666767676867696770677167726773677467756776677767786779678067816782678367846785678667876788678967906791679267936794679567966797679867996800680168026803680468056806680768086809681068116812681368146815681668176818681968206821682268236824682568266827682868296830683168326833683468356836683768386839684068416842684368446845684668476848684968506851685268536854685568566857685868596860686168626863686468656866686768686869687068716872687368746875687668776878687968806881688268836884688568866887688868896890689168926893689468956896689768986899690069016902690369046905690669076908690969106911691269136914691569166917691869196920692169226923692469256926692769286929693069316932693369346935693669376938693969406941694269436944694569466947694869496950695169526953695469556956695769586959696069616962696369646965696669676968696969706971697269736974697569766977697869796980698169826983698469856986698769886989699069916992699369946995699669976998699970007001700270037004700570067007700870097010701170127013701470157016701770187019702070217022702370247025702670277028702970307031703270337034703570367037703870397040704170427043704470457046704770487049705070517052705370547055705670577058705970607061706270637064706570667067706870697070707170727073707470757076707770787079708070817082708370847085708670877088708970907091709270937094709570967097709870997100710171027103710471057106710771087109 | 
							- {**************************************************************************************************}
 
- {                                                                                                  }
 
- { Project JEDI Code Library (JCL)                                                                  }
 
- {                                                                                                  }
 
- { The contents of this file are subject to the Mozilla Public License Version 1.1 (the "License"); }
 
- { you may not use this file except in compliance with the License. You may obtain a copy of the    }
 
- { License at http://www.mozilla.org/MPL/                                                           }
 
- {                                                                                                  }
 
- { Software distributed under the License is distributed on an "AS IS" basis, WITHOUT WARRANTY OF   }
 
- { ANY KIND, either express or implied. See the License for the specific language governing rights  }
 
- { and limitations under the License.                                                               }
 
- {                                                                                                  }
 
- { The Original Code is JclFileUtils.pas.                                                           }
 
- {                                                                                                  }
 
- { The Initial Developer of the Original Code is Marcel van Brakel.                                 }
 
- { Portions created by Marcel van Brakel are Copyright (C) Marcel van Brakel. All rights reserved.  }
 
- {                                                                                                  }
 
- { Contributors:                                                                                    }
 
- {   Andre Snepvangers (asnepvangers)                                                               }
 
- {   Andreas Hausladen (ahuser)                                                                     }
 
- {   Anthony Steele                                                                                 }
 
- {   Rik Barker (rikbarker)                                                                         }
 
- {   Azret Botash                                                                                   }
 
- {   Charlie Calvert                                                                                }
 
- {   David Hervieux                                                                                 }
 
- {   Florent Ouchet (outchy)                                                                        }
 
- {   Jean-Fabien Connault (cycocrew)                                                                }
 
- {   Jens Fudickar (jfudickar)                                                                      }
 
- {   JohnML                                                                                         }
 
- {   John Molyneux                                                                                  }
 
- {   Marcel Bestebroer                                                                              }
 
- {   Marcel van Brakel                                                                              }
 
- {   Massimo Maria Ghisalberti                                                                      }
 
- {   Matthias Thoma (mthoma)                                                                        }
 
- {   Olivier Sannier (obones)                                                                       }
 
- {   Pelle F. S. Liljendal                                                                          }
 
- {   Robert Marquardt (marquardt)                                                                   }
 
- {   Robert Rossmair (rrossmair)                                                                    }
 
- {   Rudy Velthuis                                                                                  }
 
- {   Scott Price                                                                                    }
 
- {   Wim De Cleen                                                                                   }
 
- {                                                                                                  }
 
- {**************************************************************************************************}
 
- {                                                                                                  }
 
- { This unit contains routines and classes for working with files, directories and path strings.    }
 
- { Additionally it contains wrapper classes for file mapping objects and version resources.         }
 
- { Generically speaking, everything that has to do with files and directories. Note that filesystem }
 
- { specific functionality has been extracted into external units, for example JclNTFS which         }
 
- { contains NTFS specific utility routines, and that the JclShell unit contains some file related   }
 
- { routines as well but they are specific to the Windows shell.                                     }
 
- {                                                                                                  }
 
- {**************************************************************************************************}
 
- {                                                                                                  }
 
- { Last modified: $Date::                                                                         $ }
 
- { Revision:      $Rev::                                                                          $ }
 
- { Author:        $Author::                                                                       $ }
 
- {                                                                                                  }
 
- {**************************************************************************************************}
 
- unit JclFileUtils;
 
- {$I jcl.inc}
 
- {$I crossplatform.inc}
 
- interface
 
- uses
 
-   {$IFDEF UNITVERSIONING}
 
-   JclUnitVersioning,
 
-   {$ENDIF UNITVERSIONING}
 
-   {$IFDEF HAS_UNIT_LIBC}
 
-   Libc,
 
-   {$ENDIF HAS_UNIT_LIBC}
 
-   {$IFDEF HAS_UNITSCOPE}
 
-   {$IFDEF MSWINDOWS}
 
-   Winapi.Windows, JclWin32,
 
-   {$ENDIF MSWINDOWS}
 
-   System.Classes, System.SysUtils,
 
-   {$ELSE ~HAS_UNITSCOPE}
 
-   {$IFDEF MSWINDOWS}
 
-   Windows, JclWin32,
 
-   {$ENDIF MSWINDOWS}
 
-   Classes, SysUtils,
 
-   {$ENDIF ~HAS_UNITSCOPE}
 
-   JclBase, JclSysUtils;
 
- // Path Manipulation
 
- //
 
- // Various support routines for working with path strings. For example, building a path from
 
- // elements or extracting the elements from a path, interpretation of paths and transformations of
 
- // paths.
 
- const
 
-   {$IFDEF UNIX}
 
-   // renamed to DirDelimiter
 
-   // PathSeparator    = '/';
 
-   DirDelimiter = '/';
 
-   DirSeparator = ':';
 
-   {$ENDIF UNIX}
 
-   {$IFDEF MSWINDOWS}
 
-   PathDevicePrefix = '\\.\';
 
-   // renamed to DirDelimiter
 
-   // PathSeparator    = '\';
 
-   DirDelimiter = '\';
 
-   DirSeparator = ';';
 
-   PathUncPrefix    = '\\';
 
-   {$ENDIF MSWINDOWS}
 
-   faSymLink           = $00000040 {$IFDEF SUPPORTS_PLATFORM} platform {$ENDIF}; // defined since D7
 
-   faNormalFile        = $00000080;
 
-   faTemporary         = $00000100 {$IFDEF SUPPORTS_PLATFORM} platform {$ENDIF};
 
-   faSparseFile        = $00000200 {$IFDEF SUPPORTS_PLATFORM} platform {$ENDIF};
 
-   faReparsePoint      = $00000400 {$IFDEF SUPPORTS_PLATFORM} platform {$ENDIF};
 
-   faCompressed        = $00000800 {$IFDEF SUPPORTS_PLATFORM} platform {$ENDIF};
 
-   faOffline           = $00001000 {$IFDEF SUPPORTS_PLATFORM} platform {$ENDIF};
 
-   faNotContentIndexed = $00002000 {$IFDEF SUPPORTS_PLATFORM} platform {$ENDIF};
 
-   faEncrypted         = $00004000 {$IFDEF SUPPORTS_PLATFORM} platform {$ENDIF};
 
-   // Note: faVolumeID is potentially dangerous and its usage has been discontinued
 
-   // Please see QC report 6003 for details, available online at this URL:
 
-   // http://qc.embarcadero.com/wc/qcmain.aspx?d=6003
 
-   faRejectedByDefault = faHidden + faSysFile + faDirectory;
 
-   faWindowsSpecific   = faArchive + faTemporary + faSparseFile + faReparsePoint +
 
-                         faCompressed + faOffline + faNotContentIndexed + faEncrypted;
 
-   faUnixSpecific      = faSymLink;
 
- type
 
-   TCompactPath = ({cpBegin, }cpCenter, cpEnd);
 
- function CharIsDriveLetter(const C: char): Boolean;
 
- function CharIsInvalidFileNameCharacter(const C: Char): Boolean;
 
- function CharIsInvalidPathCharacter(const C: Char): Boolean;
 
- function PathAddSeparator(const Path: string): string;
 
- function PathAddExtension(const Path, Extension: string): string;
 
- function PathAppend(const Path, Append: string): string;
 
- function PathBuildRoot(const Drive: Byte): string;
 
- function PathCanonicalize(const Path: string): string;
 
- function PathCommonPrefix(const Path1, Path2: string): Integer;
 
- {$IFDEF MSWINDOWS}
 
- function PathCompactPath(const DC: HDC; const Path: string; const Width: Integer;
 
-   CmpFmt: TCompactPath): string;
 
- {$ENDIF MSWINDOWS}
 
- procedure PathExtractElements(const Source: string; var Drive, Path, FileName, Ext: string);
 
- function PathExtractFileDirFixed(const S: string): string;
 
- function PathExtractFileNameNoExt(const Path: string): string;
 
- function PathExtractPathDepth(const Path: string; Depth: Integer): string;
 
- function PathGetDepth(const Path: string): Integer;
 
- {$IFDEF MSWINDOWS}
 
- function PathGetLongName(const Path: string): string;
 
- function PathGetShortName(const Path: string): string;
 
- {$ENDIF MSWINDOWS}
 
- function PathGetRelativePath(Origin, Destination: string): string;
 
- function PathGetTempPath: string;
 
- function PathIsAbsolute(const Path: string): Boolean;
 
- function PathIsChild(const Path, Base: string): Boolean;
 
- function PathIsEqualOrChild(const Path, Base: string): Boolean;
 
- function PathIsDiskDevice(const Path: string): Boolean;
 
- function PathIsUNC(const Path: string): Boolean;
 
- function PathRemoveSeparator(const Path: string): string;
 
- function PathRemoveExtension(const Path: string): string;
 
- // Windows Vista uses localized path names in the Windows Explorer but these
 
- // folders do not really exist on disk. This causes all I/O operations to fail
 
- // if the user specifies such a localized directory like "C:\Benutzer\MyName\Bilder"
 
- // instead of the physical folder "C:\Users\MyName\Pictures".
 
- // These two functions allow to convert the user's input from localized to
 
- // physical paths and vice versa.
 
- function PathGetPhysicalPath(const LocalizedPath: string): string;
 
- function PathGetLocalizedPath(const PhysicalPath: string): string;
 
- // Files and Directories
 
- //
 
- // Routines for working with files and directories. Includes routines to extract various file
 
- // attributes or update them, volume locking and routines for creating temporary files.
 
- type
 
-   TDelTreeProgress = function (const FileName: string; Attr: DWORD): Boolean;
 
-   TFileListOption  = (flFullNames, flRecursive, flMaskedSubfolders);
 
-   TFileListOptions = set of TFileListOption;
 
-   TJclAttributeMatch = (amAny, amExact, amSubSetOf, amSuperSetOf, amCustom);
 
-   TFileMatchFunc = function(const Attr: Integer; const FileInfo: TSearchRec): Boolean;
 
-   TFileHandler = procedure (const FileName: string) of object;
 
-   TFileHandlerEx = procedure (const Directory: string; const FileInfo: TSearchRec) of object;
 
-   TFileInfoHandlerEx = procedure (const FileInfo: TSearchRec) of object;
 
- function BuildFileList(const Path: string; const Attr: Integer; const List: TStrings; IncludeDirectoryName: Boolean =
 
-     False): Boolean;
 
- function AdvBuildFileList(const Path: string; const Attr: Integer; const Files: TStrings;
 
-   const AttributeMatch: TJclAttributeMatch = amSuperSetOf; const Options: TFileListOptions = [];
 
-   const SubfoldersMask: string = ''; const FileMatchFunc: TFileMatchFunc = nil): Boolean;
 
- function VerifyFileAttributeMask(var RejectedAttributes, RequiredAttributes: Integer): Boolean;
 
- function IsFileAttributeMatch(FileAttributes, RejectedAttributes,
 
-   RequiredAttributes: Integer): Boolean;
 
- function FileAttributesStr(const FileInfo: TSearchRec): string;
 
- function IsFileNameMatch(FileName: string; const Mask: string;
 
-   const CaseSensitive: Boolean = {$IFDEF MSWINDOWS} False {$ELSE} True {$ENDIF}): Boolean;
 
- procedure EnumFiles(const Path: string; HandleFile: TFileHandlerEx;
 
-   RejectedAttributes: Integer = faRejectedByDefault; RequiredAttributes: Integer = 0;
 
-   Abort: PBoolean = nil); overload;
 
- procedure EnumFiles(const Path: string; HandleFile: TFileInfoHandlerEx;
 
-   RejectedAttributes: Integer = faRejectedByDefault; RequiredAttributes: Integer = 0;
 
-   Abort: PBoolean = nil); overload;
 
- procedure EnumDirectories(const Root: string; const HandleDirectory: TFileHandler;
 
-   const IncludeHiddenDirectories: Boolean = False; const SubDirectoriesMask: string = '';
 
-   Abort: PBoolean = nil {$IFDEF UNIX}; ResolveSymLinks: Boolean = True {$ENDIF});
 
- {$IFDEF MSWINDOWS}
 
- procedure CreateEmptyFile(const FileName: string);
 
- function CloseVolume(var Volume: THandle): Boolean;
 
- {$IFNDEF FPC}
 
- {$IFNDEF WINSCP}
 
- function DeleteDirectory(const DirectoryName: string; MoveToRecycleBin: Boolean): Boolean;
 
- {$ENDIF ~WINSCP}
 
- function CopyDirectory(ExistingDirectoryName, NewDirectoryName: string): Boolean;
 
- function MoveDirectory(ExistingDirectoryName, NewDirectoryName: string): Boolean;
 
- {$ENDIF ~FPC}
 
- function DelTree(const Path: string): Boolean;
 
- function DelTreeEx(const Path: string; AbortOnFailure: Boolean; Progress: TDelTreeProgress): Boolean;
 
- function DiskInDrive(Drive: Char): Boolean;
 
- {$ENDIF MSWINDOWS}
 
- function DirectoryExists(const Name: string {$IFDEF UNIX}; ResolveSymLinks: Boolean = True {$ENDIF}): Boolean;
 
- function FileCreateTemp(var Prefix: string): THandle;
 
- {$IFNDEF WINSCP}
 
- function FileBackup(const FileName: string; Move: Boolean = False): Boolean;
 
- {$ENDIF ~WINSCP}
 
- function FileCopy(const ExistingFileName, NewFileName: string; ReplaceExisting: Boolean = False): Boolean;
 
- function FileDateTime(const FileName: string): TDateTime;
 
- {$IFNDEF WINSCP}
 
- function FileDelete(const FileName: string; MoveToRecycleBin: Boolean = False): Boolean;
 
- {$ENDIF ~WINSCP}
 
- function FileExists(const FileName: string): Boolean;
 
- /// <summary>procedure FileHistory Creates a list of history files of a specified
 
- /// source file. Each version of the file get's an extention .~<Nr>~ The file with
 
- /// the lowest number is the youngest file.
 
- /// </summary>
 
- /// <param name="FileName"> (string) Name of the source file</param>
 
- /// <param name="HistoryPath"> (string) Folder where the history files should be
 
- /// created. If no folder is defined the folder of the source file is used.</param>
 
- /// <param name="MaxHistoryCount"> (Integer) Max number of files</param>
 
- /// <param name="MinFileDate"> (TDateTime) Timestamp how old the file has to be to
 
- /// create a new history version. For example: NOW-1/24 => Only once per hour a new
 
- /// history file is created. Default 0 means allways
 
- /// <param name="ReplaceExtention"> (boolean) Flag to define that the history file
 
- /// extention should replace the current extention or should be added at the
 
- /// end</param>
 
- /// </param>
 
- {$IFNDEF WINSCP}
 
- procedure FileHistory(const FileName: string; HistoryPath: string = ''; MaxHistoryCount: Integer = 100; MinFileDate:
 
-     TDateTime = 0; ReplaceExtention: Boolean = true);
 
- function FileMove(const ExistingFileName, NewFileName: string; ReplaceExisting: Boolean = False): Boolean;
 
- function FileRestore(const FileName: string): Boolean;
 
- {$ENDIF ~WINSCP}
 
- function GetBackupFileName(const FileName: string): string;
 
- function IsBackupFileName(const FileName: string): Boolean;
 
- function FileGetDisplayName(const FileName: string): string;
 
- {$IFNDEF WINSCP}
 
- function FileGetGroupName(const FileName: string {$IFDEF UNIX}; ResolveSymLinks: Boolean = True {$ENDIF}): string;
 
- function FileGetOwnerName(const FileName: string {$IFDEF UNIX}; ResolveSymLinks: Boolean = True {$ENDIF}): string;
 
- {$ENDIF ~WINSCP}
 
- function FileGetSize(const FileName: string): Int64;
 
- function FileGetTempName(const Prefix: string): string;
 
- {$IFDEF MSWINDOWS}
 
- function FileGetTypeName(const FileName: string): string;
 
- {$ENDIF MSWINDOWS}
 
- function FindUnusedFileName(FileName: string; const FileExt: string; NumberPrefix: string = ''): string;
 
- function ForceDirectories(Name: string): Boolean;
 
- function GetDirectorySize(const Path: string): Int64;
 
- {$IFDEF MSWINDOWS}
 
- function GetDriveTypeStr(const Drive: Char): string;
 
- function GetFileAgeCoherence(const FileName: string): Boolean;
 
- {$ENDIF MSWINDOWS}
 
- procedure GetFileAttributeList(const Items: TStrings; const Attr: Integer);
 
- {$IFDEF MSWINDOWS}
 
- procedure GetFileAttributeListEx(const Items: TStrings; const Attr: Integer);
 
- {$ENDIF MSWINDOWS}
 
- function GetFileInformation(const FileName: string; out FileInfo: TSearchRec): Boolean; overload;
 
- function GetFileInformation(const FileName: string): TSearchRec; overload;
 
- {$IFDEF UNIX}
 
- function GetFileStatus(const FileName: string; out StatBuf: TStatBuf64;
 
-   const ResolveSymLinks: Boolean): Integer;
 
- {$ENDIF UNIX}
 
- {$IFDEF MSWINDOWS}
 
- function GetFileLastWrite(const FileName: string): TFileTime; overload;
 
- {$IFNDEF WINSCP}
 
- function GetFileLastWrite(const FileName: string; out LocalTime: TDateTime): Boolean; overload;
 
- {$ENDIF ~WINSCP}
 
- function GetFileLastAccess(const FileName: string): TFileTime; overload;
 
- {$IFNDEF WINSCP}
 
- function GetFileLastAccess(const FileName: string; out LocalTime: TDateTime): Boolean; overload;
 
- {$ENDIF ~WINSCP}
 
- function GetFileCreation(const FileName: string): TFileTime; overload;
 
- {$IFNDEF WINSCP}
 
- function GetFileCreation(const FileName: string; out LocalTime: TDateTime): Boolean; overload;
 
- {$ENDIF ~WINSCP}
 
- {$ENDIF MSWINDOWS}
 
- {$IFDEF UNIX}
 
- function GetFileLastWrite(const FileName: string; out TimeStamp: Integer; ResolveSymLinks: Boolean = True): Boolean; overload;
 
- function GetFileLastWrite(const FileName: string; out LocalTime: TDateTime; ResolveSymLinks: Boolean = True): Boolean; overload;
 
- function GetFileLastWrite(const FileName: string; ResolveSymLinks: Boolean = True): Integer; overload;
 
- function GetFileLastAccess(const FileName: string; out TimeStamp: Integer; ResolveSymLinks: Boolean = True): Boolean; overload;
 
- function GetFileLastAccess(const FileName: string; out LocalTime: TDateTime; ResolveSymLinks: Boolean = True): Boolean; overload;
 
- function GetFileLastAccess(const FileName: string; ResolveSymLinks: Boolean = True): Integer; overload;
 
- function GetFileLastAttrChange(const FileName: string; out TimeStamp: Integer; ResolveSymLinks: Boolean = True): Boolean; overload;
 
- function GetFileLastAttrChange(const FileName: string; out LocalTime: TDateTime; ResolveSymLinks: Boolean = True): Boolean; overload;
 
- function GetFileLastAttrChange(const FileName: string; ResolveSymLinks: Boolean = True): Integer; overload;
 
- {$ENDIF UNIX}
 
- function GetModulePath(const Module: HMODULE): string;
 
- function GetSizeOfFile(const FileName: string): Int64; overload;
 
- function GetSizeOfFile(const FileInfo: TSearchRec): Int64; overload;
 
- {$IFDEF MSWINDOWS}
 
- function GetSizeOfFile(Handle: THandle): Int64; overload;
 
- {$IFNDEF WINSCP}
 
- function GetStandardFileInfo(const FileName: string): TWin32FileAttributeData;
 
- {$ENDIF}
 
- {$ENDIF MSWINDOWS}
 
- function IsDirectory(const FileName: string {$IFDEF UNIX}; ResolveSymLinks: Boolean = True {$ENDIF}): Boolean;
 
- function IsRootDirectory(const CanonicFileName: string): Boolean;
 
- {$IFDEF MSWINDOWS}
 
- function LockVolume(const Volume: string; var Handle: THandle): Boolean;
 
- function OpenVolume(const Drive: Char): THandle;
 
- {$IFNDEF WINSCP}
 
- function SetDirLastWrite(const DirName: string; const DateTime: TDateTime; RequireBackupRestorePrivileges: Boolean = True): Boolean;
 
- function SetDirLastAccess(const DirName: string; const DateTime: TDateTime; RequireBackupRestorePrivileges: Boolean = True): Boolean;
 
- function SetDirCreation(const DirName: string; const DateTime: TDateTime; RequireBackupRestorePrivileges: Boolean = True): Boolean;
 
- {$ENDIF ~WINSCP}
 
- {$ENDIF MSWINDOWS}
 
- function SetFileLastWrite(const FileName: string; const DateTime: TDateTime): Boolean;
 
- function SetFileLastAccess(const FileName: string; const DateTime: TDateTime): Boolean;
 
- {$IFDEF MSWINDOWS}
 
- function SetFileCreation(const FileName: string; const DateTime: TDateTime): Boolean;
 
- procedure ShredFile(const FileName: string; Times: Integer = 1);
 
- function UnlockVolume(var Handle: THandle): Boolean;
 
- {$ENDIF MSWINDOWS}
 
- {$IFDEF UNIX}
 
- function CreateSymbolicLink(const Name, Target: string): Boolean;
 
- { This function gets the value of the symbolic link filename. }
 
- function SymbolicLinkTarget(const Name: string): string;
 
- {$ENDIF UNIX}
 
- // TJclFileAttributeMask
 
- //
 
- // File search helper class, allows to specify required/rejected attributes
 
- type
 
-   TAttributeInterest = (aiIgnored, aiRejected, aiRequired);
 
-   TJclCustomFileAttrMask = class(TPersistent)
 
-   private
 
-     FRequiredAttr: Integer;
 
-     FRejectedAttr: Integer;
 
-     function GetAttr(Index: Integer): TAttributeInterest;
 
-     procedure SetAttr(Index: Integer; const Value: TAttributeInterest);
 
-     procedure ReadRequiredAttributes(Reader: TReader);
 
-     procedure ReadRejectedAttributes(Reader: TReader);
 
-     procedure WriteRequiredAttributes(Writer: TWriter);
 
-     procedure WriteRejectedAttributes(Writer: TWriter);
 
-   protected
 
-     procedure DefineProperties(Filer: TFiler); override;
 
-     property ReadOnly: TAttributeInterest index faReadOnly
 
-       read GetAttr write SetAttr stored False;
 
-     property Hidden: TAttributeInterest index faHidden
 
-       read GetAttr write SetAttr stored False;
 
-     property System: TAttributeInterest index faSysFile
 
-       read GetAttr write SetAttr stored False;
 
-     property Directory: TAttributeInterest index faDirectory
 
-       read GetAttr write SetAttr stored False;
 
-     property SymLink: TAttributeInterest index faSymLink
 
-       read GetAttr write SetAttr stored False;
 
-     property Normal: TAttributeInterest index faNormalFile
 
-       read GetAttr write SetAttr stored False;
 
-     property Archive: TAttributeInterest index faArchive
 
-       read GetAttr write SetAttr stored False;
 
-     property Temporary: TAttributeInterest index faTemporary
 
-       read GetAttr write SetAttr stored False;
 
-     property SparseFile: TAttributeInterest index faSparseFile
 
-       read GetAttr write SetAttr stored False;
 
-     property ReparsePoint: TAttributeInterest index faReparsePoint
 
-       read GetAttr write SetAttr stored False;
 
-     property Compressed: TAttributeInterest index faCompressed
 
-       read GetAttr write SetAttr stored False;
 
-     property OffLine: TAttributeInterest index faOffline
 
-       read GetAttr write SetAttr stored False;
 
-     property NotContentIndexed: TAttributeInterest index faNotContentIndexed
 
-       read GetAttr write SetAttr stored False;
 
-     property Encrypted: TAttributeInterest index faEncrypted
 
-       read GetAttr write SetAttr stored False;
 
-   public
 
-     constructor Create;
 
-     procedure Assign(Source: TPersistent); override;
 
-     procedure Clear;
 
-     function Match(FileAttributes: Integer): Boolean; overload;
 
-     function Match(const FileInfo: TSearchRec): Boolean; overload;
 
-     property Required: Integer read FRequiredAttr write FRequiredAttr;
 
-     property Rejected: Integer read FRejectedAttr write FRejectedAttr;
 
-     property Attribute[Index: Integer]: TAttributeInterest read GetAttr write SetAttr; default;
 
-   end;
 
-   TJclFileAttributeMask = class(TJclCustomFileAttrMask)
 
-   private
 
-     procedure ReadVolumeID(Reader: TReader);
 
-   protected
 
-     procedure DefineProperties(Filer: TFiler); override;
 
-   published
 
-     property ReadOnly;
 
-     property Hidden;
 
-     property System;
 
-     property Directory;
 
-     property Normal;
 
-     {$IFDEF UNIX}
 
-     property SymLink;
 
-     {$ENDIF UNIX}
 
-     {$IFDEF MSWINDOWS}
 
-     property Archive;
 
-     property Temporary;
 
-     property SparseFile;
 
-     property ReparsePoint;
 
-     property Compressed;
 
-     property OffLine;
 
-     property NotContentIndexed;
 
-     property Encrypted;
 
-     {$ENDIF MSWINDOWS}
 
-   end;
 
- type
 
-   TFileSearchOption = (fsIncludeSubDirectories, fsIncludeHiddenSubDirectories, fsLastChangeAfter,
 
-     fsLastChangeBefore, fsMaxSize, fsMinSize);
 
-   TFileSearchOptions = set of TFileSearchOption;
 
-   TFileSearchTaskID = Integer;
 
-   TFileSearchTerminationEvent = procedure (const ID: TFileSearchTaskID; const Aborted: Boolean) of object;
 
-   TFileEnumeratorSyncMode = (smPerFile, smPerDirectory);
 
- // IJclFileSearchOptions
 
- //
 
- // Interface for file search options
 
- type
 
-   IJclFileSearchOptions = interface
 
-     ['{B73D9E3D-34C5-4DA9-88EF-4CA730328FC9}']
 
-     function GetAttributeMask: TJclFileAttributeMask;
 
-     function GetCaseSensitiveSearch: Boolean;
 
-     function GetRootDirectories: TStrings;
 
-     function GetRootDirectory: string;
 
-     function GetFileMask: string;
 
-     function GetFileMasks: TStrings;
 
-     function GetFileSizeMax: Int64;
 
-     function GetFileSizeMin: Int64;
 
-     function GetIncludeSubDirectories: Boolean;
 
-     function GetIncludeHiddenSubDirectories: Boolean;
 
-     function GetLastChangeAfter: TDateTime;
 
-     function GetLastChangeBefore: TDateTime;
 
-     function GetLastChangeAfterStr: string;
 
-     function GetLastChangeBeforeStr: string;
 
-     function GetSubDirectoryMask: string;
 
-     function GetOption(const Option: TFileSearchOption): Boolean;
 
-     function GetOptions: TFileSearchoptions;
 
-     procedure SetAttributeMask(const Value: TJclFileAttributeMask);
 
-     procedure SetCaseSensitiveSearch(const Value: Boolean);
 
-     procedure SetRootDirectories(const Value: TStrings);
 
-     procedure SetRootDirectory(const Value: string);
 
-     procedure SetFileMask(const Value: string);
 
-     procedure SetFileMasks(const Value: TStrings);
 
-     procedure SetFileSizeMax(const Value: Int64);
 
-     procedure SetFileSizeMin(const Value: Int64);
 
-     procedure SetIncludeSubDirectories(const Value: Boolean);
 
-     procedure SetIncludeHiddenSubDirectories(const Value: Boolean);
 
-     procedure SetLastChangeAfter(const Value: TDateTime);
 
-     procedure SetLastChangeBefore(const Value: TDateTime);
 
-     procedure SetLastChangeAfterStr(const Value: string);
 
-     procedure SetLastChangeBeforeStr(const Value: string);
 
-     procedure SetOption(const Option: TFileSearchOption; const Value: Boolean);
 
-     procedure SetOptions(const Value: TFileSearchOptions);
 
-     procedure SetSubDirectoryMask(const Value: string);
 
-     // properties
 
-     property CaseSensitiveSearch: Boolean read GetCaseSensitiveSearch write SetCaseSensitiveSearch;
 
-     property RootDirectories: TStrings read GetRootDirectories write SetRootDirectories;
 
-     property RootDirectory: string read GetRootDirectory write SetRootDirectory;
 
-     property FileMask: string read GetFileMask write SetFileMask;
 
-     property SubDirectoryMask: string read GetSubDirectoryMask write SetSubDirectoryMask;
 
-     property AttributeMask: TJclFileAttributeMask read GetAttributeMask write SetAttributeMask;
 
-     property FileSizeMin: Int64 read GetFileSizeMin write SetFileSizeMin;
 
-     property FileSizeMax: Int64 read GetFileSizeMax write SetFileSizeMax; // default InvalidFileSize;
 
-     property LastChangeAfter: TDateTime read GetLastChangeAfter write SetLastChangeAfter;
 
-     property LastChangeBefore: TDateTime read GetLastChangeBefore write SetLastChangeBefore;
 
-     property LastChangeAfterAsString: string read GetLastChangeAfterStr write SetLastChangeAfterStr;
 
-     property LastChangeBeforeAsString: string read GetLastChangeBeforeStr write SetLastChangeBeforeStr;
 
-     property IncludeSubDirectories: Boolean read GetIncludeSubDirectories
 
-       write SetIncludeSubDirectories;
 
-     property IncludeHiddenSubDirectories: Boolean read GetIncludeHiddenSubDirectories
 
-       write SetIncludeHiddenSubDirectories;
 
-   end;
 
- // IJclFileSearchOptions
 
- //
 
- // Interface for file search options
 
- type
 
-   TJclFileSearchOptions = class(TJclInterfacedPersistent, IJclFileSearchOptions)
 
-   protected
 
-     FFileMasks: TStringList;
 
-     FRootDirectories: TStringList;
 
-     FSubDirectoryMask: string;
 
-     FAttributeMask: TJclFileAttributeMask;
 
-     FFileSizeMin: Int64;
 
-     FFileSizeMax: Int64;
 
-     FLastChangeBefore: TDateTime;
 
-     FLastChangeAfter: TDateTime;
 
-     FOptions: TFileSearchOptions;
 
-     FCaseSensitiveSearch: Boolean;
 
-     function IsLastChangeAfterStored: Boolean;
 
-     function IsLastChangeBeforeStored: Boolean;
 
-   public
 
-     constructor Create;
 
-     destructor Destroy; override;
 
-     procedure Assign(Source: TPersistent); override;
 
-     { IJclFileSearchOptions }
 
-     function GetAttributeMask: TJclFileAttributeMask;
 
-     function GetCaseSensitiveSearch: Boolean;
 
-     function GetRootDirectories: TStrings;
 
-     function GetRootDirectory: string;
 
-     function GetFileMask: string;
 
-     function GetFileMasks: TStrings;
 
-     function GetFileSizeMax: Int64;
 
-     function GetFileSizeMin: Int64;
 
-     function GetIncludeSubDirectories: Boolean;
 
-     function GetIncludeHiddenSubDirectories: Boolean;
 
-     function GetLastChangeAfter: TDateTime;
 
-     function GetLastChangeBefore: TDateTime;
 
-     function GetLastChangeAfterStr: string;
 
-     function GetLastChangeBeforeStr: string;
 
-     function GetSubDirectoryMask: string;
 
-     function GetOption(const Option: TFileSearchOption): Boolean;
 
-     function GetOptions: TFileSearchoptions;
 
-     procedure SetAttributeMask(const Value: TJclFileAttributeMask);
 
-     procedure SetCaseSensitiveSearch(const Value: Boolean);
 
-     procedure SetRootDirectories(const Value: TStrings);
 
-     procedure SetRootDirectory(const Value: string);
 
-     procedure SetFileMask(const Value: string);
 
-     procedure SetFileMasks(const Value: TStrings);
 
-     procedure SetFileSizeMax(const Value: Int64);
 
-     procedure SetFileSizeMin(const Value: Int64);
 
-     procedure SetIncludeSubDirectories(const Value: Boolean);
 
-     procedure SetIncludeHiddenSubDirectories(const Value: Boolean);
 
-     procedure SetLastChangeAfter(const Value: TDateTime);
 
-     procedure SetLastChangeBefore(const Value: TDateTime);
 
-     procedure SetLastChangeAfterStr(const Value: string);
 
-     procedure SetLastChangeBeforeStr(const Value: string);
 
-     procedure SetOption(const Option: TFileSearchOption; const Value: Boolean);
 
-     procedure SetOptions(const Value: TFileSearchOptions);
 
-     procedure SetSubDirectoryMask(const Value: string);
 
-   published
 
-     property CaseSensitiveSearch: Boolean read GetCaseSensitiveSearch write SetCaseSensitiveSearch
 
-       default {$IFDEF MSWINDOWS} False {$ELSE} True {$ENDIF};
 
-     property FileMasks: TStrings read GetFileMasks write SetFileMasks;
 
-     property RootDirectories: TStrings read GetRootDirectories write SetRootDirectories;
 
-     property RootDirectory: string read GetRootDirectory write SetRootDirectory;
 
-     property SubDirectoryMask: string read FSubDirectoryMask write FSubDirectoryMask;
 
-     property AttributeMask: TJclFileAttributeMask read FAttributeMask write SetAttributeMask;
 
-     property FileSizeMin: Int64 read FFileSizeMin write FFileSizeMin;
 
-     property FileSizeMax: Int64 read FFileSizeMax write FFileSizeMax;
 
-     property LastChangeAfter: TDateTime read FLastChangeAfter write FLastChangeAfter
 
-       stored IsLastChangeAfterStored;
 
-     property LastChangeBefore: TDateTime read FLastChangeBefore write FLastChangeBefore
 
-       stored IsLastChangeBeforeStored;
 
-     property Options: TFileSearchOptions read FOptions write FOptions
 
-       default [fsIncludeSubDirectories];
 
-   end;
 
- // IJclFileEnumerator
 
- //
 
- // Interface for thread-based file search
 
- type
 
-   IJclFileEnumerator = interface(IJclFileSearchOptions)
 
-     ['{F7E747ED-1C41-441F-B25B-BB314E00C4E9}']
 
-     // property access methods
 
-     function GetRunningTasks: Integer;
 
-     function GetSynchronizationMode: TFileEnumeratorSyncMode;
 
-     function GetOnEnterDirectory: TFileHandler;
 
-     function GetOnTerminateTask: TFileSearchTerminationEvent;
 
-     procedure SetSynchronizationMode(const Value: TFileEnumeratorSyncMode);
 
-     procedure SetOnEnterDirectory(const Value: TFileHandler);
 
-     procedure SetOnTerminateTask(const Value: TFileSearchTerminationEvent);
 
-     // other methods
 
-     function FillList(List: TStrings): TFileSearchTaskID;
 
-     function ForEach(Handler: TFileHandler): TFileSearchTaskID; overload;
 
-     function ForEach(Handler: TFileHandlerEx): TFileSearchTaskID; overload;
 
-     procedure StopTask(ID: TFileSearchTaskID);
 
-     procedure StopAllTasks(Silently: Boolean = False); // Silently: Don't call OnTerminateTask
 
-     // properties
 
-     property RunningTasks: Integer read GetRunningTasks;
 
-     property SynchronizationMode: TFileEnumeratorSyncMode read GetSynchronizationMode
 
-       write SetSynchronizationMode;
 
-     property OnEnterDirectory: TFileHandler read GetOnEnterDirectory write SetOnEnterDirectory;
 
-     property OnTerminateTask: TFileSearchTerminationEvent read GetOnTerminateTask
 
-       write SetOnTerminateTask;
 
-   end;
 
- // TJclFileEnumerator
 
- //
 
- // Class for thread-based file search
 
- type
 
-   TJclFileEnumerator = class(TJclFileSearchOptions, IInterface, IJclFileSearchOptions, IJclFileEnumerator)
 
-   private
 
-     FTasks: TList;
 
-     FOnEnterDirectory: TFileHandler;
 
-     FOnTerminateTask: TFileSearchTerminationEvent;
 
-     FNextTaskID: TFileSearchTaskID;
 
-     FSynchronizationMode: TFileEnumeratorSyncMode;
 
-     function GetNextTaskID: TFileSearchTaskID;
 
-   protected
 
-     function CreateTask: TThread;
 
-     procedure TaskTerminated(Sender: TObject);
 
-     property NextTaskID: TFileSearchTaskID read GetNextTaskID;
 
-   public
 
-     constructor Create;
 
-     destructor Destroy; override;
 
-     { IJclFileEnumerator }
 
-     function GetRunningTasks: Integer;
 
-     function GetSynchronizationMode: TFileEnumeratorSyncMode;
 
-     function GetOnEnterDirectory: TFileHandler;
 
-     function GetOnTerminateTask: TFileSearchTerminationEvent;
 
-     procedure SetSynchronizationMode(const Value: TFileEnumeratorSyncMode);
 
-     procedure SetOnEnterDirectory(const Value: TFileHandler);
 
-     procedure SetOnTerminateTask(const Value: TFileSearchTerminationEvent);
 
-     procedure Assign(Source: TPersistent); override;
 
-     function FillList(List: TStrings): TFileSearchTaskID;
 
-     function ForEach(Handler: TFileHandler): TFileSearchTaskID; overload;
 
-     function ForEach(Handler: TFileHandlerEx): TFileSearchTaskID; overload;
 
-     procedure StopTask(ID: TFileSearchTaskID);
 
-     procedure StopAllTasks(Silently: Boolean = False); // Silently: Don't call OnTerminateTask
 
-     property FileMask: string read GetFileMask write SetFileMask;
 
-     property IncludeSubDirectories: Boolean
 
-       read GetIncludeSubDirectories write SetIncludeSubDirectories;
 
-     property IncludeHiddenSubDirectories: Boolean
 
-       read GetIncludeHiddenSubDirectories write SetIncludeHiddenSubDirectories;
 
-     property SearchOption[const Option: TFileSearchOption]: Boolean read GetOption write SetOption;
 
-     property LastChangeAfterAsString: string read GetLastChangeAfterStr write SetLastChangeAfterStr;
 
-     property LastChangeBeforeAsString: string read GetLastChangeBeforeStr write SetLastChangeBeforeStr;
 
-   published
 
-     property RunningTasks: Integer read GetRunningTasks;
 
-     property SynchronizationMode: TFileEnumeratorSyncMode read FSynchronizationMode write FSynchronizationMode
 
-       default smPerDirectory;
 
-     property OnEnterDirectory: TFileHandler read FOnEnterDirectory write FOnEnterDirectory;
 
-     property OnTerminateTask: TFileSearchTerminationEvent read FOnTerminateTask write FOnTerminateTask;
 
-   end;
 
- function FileSearch: IJclFileEnumerator;
 
- {$IFDEF MSWINDOWS}
 
- // TFileVersionInfo
 
- //
 
- // Class that enables reading the version information stored in a PE file.
 
- type
 
-   TFileFlag = (ffDebug, ffInfoInferred, ffPatched, ffPreRelease, ffPrivateBuild, ffSpecialBuild);
 
-   TFileFlags = set of TFileFlag;
 
-   PLangIdRec = ^TLangIdRec;
 
-   TLangIdRec = packed record
 
-     case Integer of
 
-     0: (
 
-       LangId: Word;
 
-       CodePage: Word);
 
-     1: (
 
-       Pair: DWORD);
 
-   end;
 
-   EJclFileVersionInfoError = class(EJclError);
 
-   TJclFileVersionInfo = class(TObject)
 
-   private
 
-     FBuffer: AnsiString;
 
-     FFixedInfo: PVSFixedFileInfo;
 
-     FFileFlags: TFileFlags;
 
-     FItemList: TStringList;
 
-     FItems: TStringList;
 
-     FLanguages: array of TLangIdRec;
 
-     FLanguageIndex: Integer;
 
-     FTranslations: array of TLangIdRec;
 
-     function GetFixedInfo: TVSFixedFileInfo;
 
-     function GetItems: TStrings;
 
-     function GetLanguageCount: Integer;
 
-     function GetLanguageIds(Index: Integer): string;
 
-     function GetLanguageNames(Index: Integer): string;
 
-     function GetLanguages(Index: Integer): TLangIdRec;
 
-     function GetTranslationCount: Integer;
 
-     function GetTranslations(Index: Integer): TLangIdRec;
 
-     procedure SetLanguageIndex(const Value: Integer);
 
-   protected
 
-     procedure CreateItemsForLanguage;
 
-     procedure CheckLanguageIndex(Value: Integer);
 
-     procedure ExtractData;
 
-     procedure ExtractFlags;
 
-     function GetBinFileVersion: string;
 
-     function GetBinProductVersion: string;
 
-     function GetFileOS: DWORD;
 
-     function GetFileSubType: DWORD;
 
-     function GetFileType: DWORD;
 
-     function GetFileVersionBuild: string;
 
-     function GetFileVersionMajor: string;
 
-     function GetFileVersionMinor: string;
 
-     function GetFileVersionRelease: string;
 
-     function GetProductVersionBuild: string;
 
-     function GetProductVersionMajor: string;
 
-     function GetProductVersionMinor: string;
 
-     function GetProductVersionRelease: string;
 
-     function GetVersionKeyValue(Index: Integer): string;
 
-   public
 
-     constructor Attach(VersionInfoData: Pointer; Size: Integer);
 
-     constructor Create(const FileName: string); overload;
 
-     {$IFDEF MSWINDOWS}
 
-     {$IFDEF FPC}
 
-     constructor Create(const Window: HWND; Dummy: Pointer = nil); overload;
 
-     {$ELSE}
 
-     constructor Create(const Window: HWND); overload;
 
-     {$ENDIF}
 
-     constructor Create(const Module: HMODULE); overload;
 
-     {$ENDIF MSWINDOWS}
 
-     destructor Destroy; override;
 
-     function GetCustomFieldValue(const FieldName: string): string;
 
-     class function VersionLanguageId(const LangIdRec: TLangIdRec): string;
 
-     class function VersionLanguageName(const LangId: Word): string;
 
-     class function FileHasVersionInfo(const FileName: string): boolean;
 
-     function TranslationMatchesLanguages(Exact: Boolean = True): Boolean;
 
-     property BinFileVersion: string read GetBinFileVersion;
 
-     property BinProductVersion: string read GetBinProductVersion;
 
-     property Comments: string index 1 read GetVersionKeyValue;
 
-     property CompanyName: string index 2 read GetVersionKeyValue;
 
-     property FileDescription: string index 3 read GetVersionKeyValue;
 
-     property FixedInfo: TVSFixedFileInfo read GetFixedInfo;
 
-     property FileFlags: TFileFlags read FFileFlags;
 
-     property FileOS: DWORD read GetFileOS;
 
-     property FileSubType: DWORD read GetFileSubType;
 
-     property FileType: DWORD read GetFileType;
 
-     property FileVersion: string index 4 read GetVersionKeyValue;
 
-     property FileVersionBuild: string read GetFileVersionBuild;
 
-     property FileVersionMajor: string read GetFileVersionMajor;
 
-     property FileVersionMinor: string read GetFileVersionMinor;
 
-     property FileVersionRelease: string read GetFileVersionRelease;
 
-     property Items: TStrings read GetItems;
 
-     property InternalName: string index 5 read GetVersionKeyValue;
 
-     property LanguageCount: Integer read GetLanguageCount;
 
-     property LanguageIds[Index: Integer]: string read GetLanguageIds;
 
-     property LanguageIndex: Integer read FLanguageIndex write SetLanguageIndex;
 
-     property Languages[Index: Integer]: TLangIdRec read GetLanguages;
 
-     property LanguageNames[Index: Integer]: string read GetLanguageNames;
 
-     property LegalCopyright: string index 6 read GetVersionKeyValue;
 
-     property LegalTradeMarks: string index 7 read GetVersionKeyValue;
 
-     property OriginalFilename: string index 8 read GetVersionKeyValue;
 
-     property PrivateBuild: string index 12 read GetVersionKeyValue;
 
-     property ProductName: string index 9 read GetVersionKeyValue;
 
-     property ProductVersion: string index 10 read GetVersionKeyValue;
 
-     property ProductVersionBuild: string read GetProductVersionBuild;
 
-     property ProductVersionMajor: string read GetProductVersionMajor;
 
-     property ProductVersionMinor: string read GetProductVersionMinor;
 
-     property ProductVersionRelease: string read GetProductVersionRelease;
 
-     property SpecialBuild: string index 11 read GetVersionKeyValue;
 
-     property TranslationCount: Integer read GetTranslationCount;
 
-     property Translations[Index: Integer]: TLangIdRec read GetTranslations;
 
-   end;
 
- function OSIdentToString(const OSIdent: DWORD): string;
 
- function OSFileTypeToString(const OSFileType: DWORD; const OSFileSubType: DWORD = 0): string;
 
- function VersionResourceAvailable(const FileName: string): Boolean; overload;
 
- function VersionResourceAvailable(const Window: HWND): Boolean; overload;
 
- function VersionResourceAvailable(const Module: HMODULE): Boolean; overload;
 
- function WindowToModuleFileName(const Window: HWND): string;
 
- {$ENDIF MSWINDOWS}
 
- // Version Info formatting
 
- type
 
-   TFileVersionFormat = (vfMajorMinor, vfFull);
 
- function FormatVersionString(const HiV, LoV: Word): string; overload;
 
- function FormatVersionString(const Major, Minor, Build, Revision: Word): string; overload;
 
- {$IFDEF MSWINDOWS}
 
- function FormatVersionString(const FixedInfo: TVSFixedFileInfo; VersionFormat: TFileVersionFormat = vfFull): string; overload;
 
- // Version Info extracting
 
- procedure VersionExtractFileInfo(const FixedInfo: TVSFixedFileInfo; var Major, Minor, Build, Revision: Word);
 
- procedure VersionExtractProductInfo(const FixedInfo: TVSFixedFileInfo; var Major, Minor, Build, Revision: Word);
 
- // Fixed Version Info routines
 
- function VersionFixedFileInfo(const FileName: string; var FixedInfo: TVSFixedFileInfo): Boolean;
 
- function VersionFixedFileInfoString(const FileName: string; VersionFormat: TFileVersionFormat = vfFull;
 
-   const NotAvailableText: string = ''): string;
 
- {$ENDIF MSWINDOWS}
 
- // Streams
 
- //
 
- // TStream descendent classes for dealing with temporary files and for using file mapping objects.
 
- type
 
-   TJclTempFileStream = class(THandleStream)
 
-   private
 
-     FFileName: string;
 
-   public
 
-     constructor Create(const Prefix: string);
 
-     destructor Destroy; override;
 
-     property FileName: string read FFileName;
 
-   end;
 
- {$IFDEF MSWINDOWS}
 
-   TJclCustomFileMapping = class;
 
-   TJclFileMappingView = class(TCustomMemoryStream)
 
-   private
 
-     FFileMapping: TJclCustomFileMapping;
 
-     FOffsetHigh: Cardinal;
 
-     FOffsetLow: Cardinal;
 
-     function GetIndex: Integer;
 
-     function GetOffset: Int64;
 
-   public
 
-     constructor Create(const FileMap: TJclCustomFileMapping;
 
-       Access, Size: Cardinal; ViewOffset: Int64);
 
-     constructor CreateAt(FileMap: TJclCustomFileMapping; Access,
 
-       Size: Cardinal; ViewOffset: Int64; Address: Pointer);
 
-     destructor Destroy; override;
 
-     function Flush(const Count: Cardinal): Boolean;
 
-     procedure LoadFromStream(const Stream: TStream);
 
-     procedure LoadFromFile(const FileName: string);
 
-     function Write(const Buffer; Count: Longint): Longint; override;
 
-     property Index: Integer read GetIndex;
 
-     property FileMapping: TJclCustomFileMapping read FFileMapping;
 
-     property Offset: Int64 read GetOffset;
 
-   end;
 
-   TJclFileMappingRoundOffset = (rvDown, rvUp);
 
-   TJclCustomFileMapping = class(TObject)
 
-   private
 
-     FExisted: Boolean;
 
-     FHandle: THandle;
 
-     FName: string;
 
-     FRoundViewOffset: TJclFileMappingRoundOffset;
 
-     FViews: TList;
 
-     function GetCount: Integer;
 
-     function GetView(Index: Integer): TJclFileMappingView;
 
-   protected
 
-     procedure ClearViews;
 
-     procedure InternalCreate(const FileHandle: THandle; const Name: string;
 
-       const Protect: Cardinal; MaximumSize: Int64; SecAttr: PSecurityAttributes);
 
-     procedure InternalOpen(const Name: string; const InheritHandle: Boolean;
 
-       const DesiredAccess: Cardinal);
 
-   public
 
-     constructor Create;
 
-     constructor Open(const Name: string; const InheritHandle: Boolean; const DesiredAccess: Cardinal);
 
-     destructor Destroy; override;
 
-     function Add(const Access, Count: Cardinal; const Offset: Int64): Integer;
 
-     function AddAt(const Access, Count: Cardinal; const Offset: Int64; const Address: Pointer): Integer;
 
-     procedure Delete(const Index: Integer);
 
-     function IndexOf(const View: TJclFileMappingView): Integer;
 
-     property Count: Integer read GetCount;
 
-     property Existed: Boolean read FExisted;
 
-     property Handle: THandle read FHandle;
 
-     property Name: string read FName;
 
-     property RoundViewOffset: TJclFileMappingRoundOffset read FRoundViewOffset write FRoundViewOffset;
 
-     property Views[index: Integer]: TJclFileMappingView read GetView;
 
-   end;
 
-   TJclFileMapping = class(TJclCustomFileMapping)
 
-   private
 
-     FFileHandle: THandle;
 
-   public
 
-     constructor Create(const FileName: string; FileMode: Cardinal;
 
-       const Name: string; Protect: Cardinal; const MaximumSize: Int64;
 
-       SecAttr: PSecurityAttributes); overload;
 
-     constructor Create(const FileHandle: THandle; const Name: string;
 
-       Protect: Cardinal; const MaximumSize: Int64;
 
-       SecAttr: PSecurityAttributes); overload;
 
-     destructor Destroy; override;
 
-     property FileHandle: THandle read FFileHandle;
 
-   end;
 
-   TJclSwapFileMapping = class(TJclCustomFileMapping)
 
-   public
 
-     constructor Create(const Name: string; Protect: Cardinal;
 
-       const MaximumSize: Int64; SecAttr: PSecurityAttributes);
 
-   end;
 
-   TJclFileMappingStream = class(TCustomMemoryStream)
 
-   private
 
-     FFileHandle: THandle;
 
-     FMapping: THandle;
 
-   protected
 
-     procedure Close;
 
-   public
 
-     constructor Create(const FileName: string; FileMode: Word = fmOpenRead or fmShareDenyWrite);
 
-     destructor Destroy; override;
 
-     function Write(const Buffer; Count: Longint): Longint; override;
 
-   end;
 
- {$ENDIF MSWINDOWS}
 
-   TJclMappedTextReaderIndex = (tiNoIndex, tiFull);
 
-   PPAnsiCharArray = ^TPAnsiCharArray;
 
-   TPAnsiCharArray = array [0..MaxInt div SizeOf(PAnsiChar) - 1] of PAnsiChar;
 
-   TJclAnsiMappedTextReader = class(TPersistent)
 
-   private
 
-     FContent: PAnsiChar;
 
-     FEnd: PAnsiChar;
 
-     FIndex: PPAnsiCharArray;
 
-     FIndexOption: TJclMappedTextReaderIndex;
 
-     FFreeStream: Boolean;
 
-     FLastLineNumber: Integer;
 
-     FLastPosition: PAnsiChar;
 
-     FLineCount: Integer;
 
-     FMemoryStream: TCustomMemoryStream;
 
-     FPosition: PAnsiChar;
 
-     FSize: Integer;
 
-     function GetAsString: AnsiString;
 
-     function GetEof: Boolean;
 
-     function GetChars(Index: Integer): AnsiChar;
 
-     function GetLineCount: Integer;
 
-     function GetLines(LineNumber: Integer): AnsiString;
 
-     function GetPosition: Integer;
 
-     function GetPositionFromLine(LineNumber: Integer): Integer;
 
-     procedure SetPosition(const Value: Integer);
 
-   protected
 
-     procedure AssignTo(Dest: TPersistent); override;
 
-     procedure CreateIndex;
 
-     procedure Init;
 
-     function PtrFromLine(LineNumber: Integer): PAnsiChar;
 
-     function StringFromPosition(var StartPos: PAnsiChar): AnsiString;
 
-   public
 
-     constructor Create(MemoryStream: TCustomMemoryStream; FreeStream: Boolean = True;
 
-       const AIndexOption: TJclMappedTextReaderIndex = tiNoIndex); overload;
 
-     constructor Create(const FileName: TFileName;
 
-       const AIndexOption: TJclMappedTextReaderIndex = tiNoIndex); overload;
 
-     destructor Destroy; override;
 
-     procedure GoBegin;
 
-     function Read: AnsiChar;
 
-     function ReadLn: AnsiString;
 
-     property AsString: AnsiString read GetAsString;
 
-     property Chars[Index: Integer]: AnsiChar read GetChars;
 
-     property Content: PAnsiChar read FContent;
 
-     property Eof: Boolean read GetEof;
 
-     property IndexOption: TJclMappedTextReaderIndex read FIndexOption;
 
-     property Lines[LineNumber: Integer]: AnsiString read GetLines;
 
-     property LineCount: Integer read GetLineCount;
 
-     property PositionFromLine[LineNumber: Integer]: Integer read GetPositionFromLine;
 
-     property Position: Integer read GetPosition write SetPosition;
 
-     property Size: Integer read FSize;
 
-   end;
 
-   PPWideCharArray = ^TPWideCharArray;
 
-   TPWideCharArray = array [0..MaxInt div SizeOf(PWideChar) - 1] of PWideChar;
 
-   TJclWideMappedTextReader = class(TPersistent)
 
-   private
 
-     FContent: PWideChar;
 
-     FEnd: PWideChar;
 
-     FIndex: PPWideCharArray;
 
-     FIndexOption: TJclMappedTextReaderIndex;
 
-     FFreeStream: Boolean;
 
-     FLastLineNumber: Integer;
 
-     FLastPosition: PWideChar;
 
-     FLineCount: Integer;
 
-     FMemoryStream: TCustomMemoryStream;
 
-     FPosition: PWideChar;
 
-     FSize: Integer;
 
-     function GetAsString: WideString;
 
-     function GetEof: Boolean;
 
-     function GetChars(Index: Integer): WideChar;
 
-     function GetLineCount: Integer;
 
-     function GetLines(LineNumber: Integer): WideString;
 
-     function GetPosition: Integer;
 
-     function GetPositionFromLine(LineNumber: Integer): Integer;
 
-     procedure SetPosition(const Value: Integer);
 
-   protected
 
-     procedure AssignTo(Dest: TPersistent); override;
 
-     procedure CreateIndex;
 
-     procedure Init;
 
-     function PtrFromLine(LineNumber: Integer): PWideChar;
 
-     function StringFromPosition(var StartPos: PWideChar): WideString;
 
-   public
 
-     constructor Create(MemoryStream: TCustomMemoryStream; FreeStream: Boolean = True;
 
-       const AIndexOption: TJclMappedTextReaderIndex = tiNoIndex); overload;
 
-     constructor Create(const FileName: TFileName;
 
-       const AIndexOption: TJclMappedTextReaderIndex = tiNoIndex); overload;
 
-     destructor Destroy; override;
 
-     procedure GoBegin;
 
-     function Read: WideChar;
 
-     function ReadLn: WideString;
 
-     property AsString: WideString read GetAsString;
 
-     property Chars[Index: Integer]: WideChar read GetChars;
 
-     property Content: PWideChar read FContent;
 
-     property Eof: Boolean read GetEof;
 
-     property IndexOption: TJclMappedTextReaderIndex read FIndexOption;
 
-     property Lines[LineNumber: Integer]: WideString read GetLines;
 
-     property LineCount: Integer read GetLineCount;
 
-     property PositionFromLine[LineNumber: Integer]: Integer read GetPositionFromLine;
 
-     property Position: Integer read GetPosition write SetPosition;
 
-     property Size: Integer read FSize;
 
-   end;
 
- { TODO : UNTESTED/UNDOCUMENTED }
 
- type
 
-   TJclFileMaskComparator = class(TObject)
 
-   private
 
-     FFileMask: string;
 
-     FExts: array of string;
 
-     FNames: array of string;
 
-     FWildChars: array of Byte;
 
-     FSeparator: Char;
 
-     procedure CreateMultiMasks;
 
-     function GetCount: Integer;
 
-     function GetExts(Index: Integer): string;
 
-     function GetMasks(Index: Integer): string;
 
-     function GetNames(Index: Integer): string;
 
-     procedure SetFileMask(const Value: string);
 
-     procedure SetSeparator(const Value: Char);
 
-   public
 
-     constructor Create;
 
-     function Compare(const NameExt: string): Boolean;
 
-     property Count: Integer read GetCount;
 
-     property Exts[Index: Integer]: string read GetExts;
 
-     property FileMask: string read FFileMask write SetFileMask;
 
-     property Masks[Index: Integer]: string read GetMasks;
 
-     property Names[Index: Integer]: string read GetNames;
 
-     property Separator: Char read FSeparator write SetSeparator;
 
-   end;
 
-   EJclPathError = class(EJclError);
 
-   EJclFileUtilsError = class(EJclError);
 
-   {$IFDEF UNIX}
 
-   EJclTempFileStreamError = class(EJclFileUtilsError);
 
-   {$ENDIF UNIX}
 
-   {$IFDEF MSWINDOWS}
 
-   EJclTempFileStreamError = class(EJclWin32Error);
 
-   EJclFileMappingError = class(EJclWin32Error);
 
-   EJclFileMappingViewError = class(EJclWin32Error);
 
-   {$ENDIF MSWINDOWS}
 
- function SamePath(const Path1, Path2: string): Boolean;
 
- // functions to add/delete paths from a separated list of paths
 
- // on windows the separator is a semi-colon ';'
 
- // on linux the separator is a colon ':'
 
- // add items at the end
 
- procedure PathListAddItems(var List: string; const Items: string);
 
- // add items at the end if they are not present
 
- procedure PathListIncludeItems(var List: string; const Items: string);
 
- // delete multiple items
 
- procedure PathListDelItems(var List: string; const Items: string);
 
- // delete one item
 
- procedure PathListDelItem(var List: string; const Index: Integer);
 
- // return the number of item
 
- function PathListItemCount(const List: string): Integer;
 
- // return the Nth item
 
- function PathListGetItem(const List: string; const Index: Integer): string;
 
- // set the Nth item
 
- procedure PathListSetItem(var List: string; const Index: Integer; const Value: string);
 
- // return the index of an item
 
- function PathListItemIndex(const List, Item: string): Integer;
 
- // additional functions to access the commandline parameters of an application
 
- // returns the name of the command line parameter at position index, which is
 
- // separated by the given separator, if the first character of the name part
 
- // is one of the AllowedPrefixCharacters, this character will be deleted.
 
- function ParamName(Index: Integer; const Separator: string = '=';
 
-   const AllowedPrefixCharacters: string = '-/'; TrimName: Boolean = True): string;
 
- // returns the value of the command line parameter at position index, which is
 
- // separated by the given separator
 
- function ParamValue (Index: Integer; const Separator: string = '='; TrimValue: Boolean = True): string; overload;
 
- // seaches a command line parameter where the namepart is the searchname
 
- // and returns the value which is which by the given separator.
 
- // CaseSensitive defines the search type. if the first character of the name part
 
- // is one of the AllowedPrefixCharacters, this character will be deleted.
 
- function ParamValue (const SearchName: string; const Separator: string = '=';
 
-              CaseSensitive: Boolean = False;
 
-              const AllowedPrefixCharacters: string = '-/'; TrimValue: Boolean = True): string; overload;
 
- // seaches a command line parameter where the namepart is the searchname
 
- // and returns the position index. if no separator is defined, the full paramstr is compared.
 
- // CaseSensitive defines the search type. if the first character of the name part
 
- // is one of the AllowedPrefixCharacters, this character will be deleted.
 
- function ParamPos (const SearchName: string; const Separator: string = '=';
 
-              CaseSensitive: Boolean = False;
 
-              const AllowedPrefixCharacters: string = '-/'): Integer;
 
- {$IFDEF UNITVERSIONING}
 
- const
 
-   UnitVersioning: TUnitVersionInfo = (
 
-     RCSfile: '$URL$';
 
-     Revision: '$Revision$';
 
-     Date: '$Date$';
 
-     LogPath: 'JCL\source\common';
 
-     Extra: '';
 
-     Data: nil
 
-     );
 
- {$ENDIF UNITVERSIONING}
 
- implementation
 
- uses
 
-   {$IFDEF HAS_UNITSCOPE}
 
-   System.Types, // inlining of TList.Remove
 
-   {$IFDEF HAS_UNIT_CHARACTER}
 
-   System.Character,
 
-   {$ENDIF HAS_UNIT_CHARACTER}
 
-   System.Math,
 
-   {$IFDEF MSWINDOWS}
 
-   Winapi.ShellApi, Winapi.ActiveX, System.Win.ComObj, Winapi.ShlObj,
 
-   {$IFNDEF WINSCP}JclShell,{$ENDIF ~WINSCP} JclSysInfo, {$IFNDEF WINSCP}JclSecurity,{$ENDIF ~WINSCP}
 
-   {$ENDIF MSWINDOWS}
 
-   {$ELSE ~HAS_UNITSCOPE}
 
-   {$IFDEF HAS_UNIT_CHARACTER}
 
-   Character,
 
-   {$ENDIF HAS_UNIT_CHARACTER}
 
-   Math,
 
-   {$IFDEF MSWINDOWS}
 
-   ShellApi, ActiveX, ComObj, ShlObj,
 
-   JclShell, JclSysInfo, JclSecurity,
 
-   {$ENDIF MSWINDOWS}
 
-   {$ENDIF ~HAS_UNITSCOPE}
 
-   {$IFNDEF WINSCP}JclDateTime,{$ENDIF ~WINSCP} JclResources,
 
-   JclStrings;
 
- { Some general notes:
 
-   This unit redeclares some functions from FileCtrl.pas to avoid a dependency on that unit in the
 
-   JCL. The problem is that FileCtrl.pas uses some units (eg Forms.pas) which have ridiculous
 
-   initialization requirements. They add 4KB (!) to the executable and roughly 1 second of startup.
 
-   That initialization is only necessary for GUI applications and is unacceptable for high
 
-   performance services or console apps.
 
-   The routines which query files or directories for their attributes deliberately use FindFirst
 
-   even though there may be easier ways to get at the required information. This is because FindFirst
 
-   is about the only routine which doesn't cause the file's last modification/accessed time to be
 
-   changed which is usually an undesired side-effect. }
 
- {$IFDEF UNIX}
 
- const
 
-   ERROR_NO_MORE_FILES  = -1;
 
-   INVALID_HANDLE_VALUE = THandle(-1);
 
- {$ENDIF UNIX}
 
- //=== { TJclTempFileStream } =================================================
 
- constructor TJclTempFileStream.Create(const Prefix: string);
 
- var
 
-   FileHandle: THandle;
 
- begin
 
-   FFileName := Prefix;
 
-   FileHandle := FileCreateTemp(FFileName);
 
-   // (rom) is it really wise to throw an exception before calling inherited?
 
-   if FileHandle = INVALID_HANDLE_VALUE then
 
-     raise EJclTempFileStreamError.CreateRes(@RsFileStreamCreate);
 
-   inherited Create(FileHandle);
 
- end;
 
- destructor TJclTempFileStream.Destroy;
 
- begin
 
-   if THandle(Handle) <> INVALID_HANDLE_VALUE then
 
-     FileClose(Handle);
 
-   inherited Destroy;
 
- end;
 
- //=== { TJclFileMappingView } ================================================
 
- {$IFDEF MSWINDOWS}
 
- constructor TJclFileMappingView.Create(const FileMap: TJclCustomFileMapping;
 
-   Access, Size: Cardinal; ViewOffset: Int64);
 
- var
 
-   BaseAddress: Pointer;
 
-   OffsetLow, OffsetHigh: Cardinal;
 
- begin
 
-   inherited Create;
 
-   if FileMap = nil then
 
-     raise EJclFileMappingViewError.CreateRes(@RsViewNeedsMapping);
 
-   FFileMapping := FileMap;
 
-   // Offset must be a multiple of system memory allocation granularity
 
-   RoundToAllocGranularity64(ViewOffset, FFileMapping.RoundViewOffset = rvUp);
 
-   I64ToCardinals(ViewOffset, OffsetLow, OffsetHigh);
 
-   FOffsetHigh := OffsetHigh;
 
-   FOffsetLow := OffsetLow;
 
-   BaseAddress := MapViewOfFile(FFileMapping.Handle, Access, FOffsetHigh, FOffsetLow, Size);
 
-   if BaseAddress = nil then
 
-     raise EJclFileMappingViewError.CreateRes(@RsCreateFileMappingView);
 
-   // If we are mapping a file and size = 0 then MapViewOfFile has mapped the entire file. We must
 
-   // figure out the size ourselves before we can call SetPointer. Since in case of failure to
 
-   // retrieve the size we raise an exception, we also have to explicitly unmap the view which
 
-   // otherwise would have been done by the destructor.
 
-   if (Size = 0) and (FileMap is TJclFileMapping) then
 
-   begin
 
-     Size := GetFileSize(TJclFileMapping(FileMap).FFileHandle, nil);
 
-     if Size = DWORD(-1) then
 
-     begin
 
-       UnMapViewOfFile(BaseAddress);
 
-       raise EJclFileMappingViewError.CreateRes(@RsFailedToObtainSize);
 
-     end;
 
-   end;
 
-   SetPointer(BaseAddress, Size);
 
-   FFileMapping.FViews.Add(Self);
 
- end;
 
- constructor TJclFileMappingView.CreateAt(FileMap: TJclCustomFileMapping;
 
-   Access, Size: Cardinal; ViewOffset: Int64; Address: Pointer);
 
- var
 
-   BaseAddress: Pointer;
 
-   OffsetLow, OffsetHigh: Cardinal;
 
- begin
 
-   inherited Create;
 
-   if FileMap = nil then
 
-     raise EJclFileMappingViewError.CreateRes(@RsViewNeedsMapping);
 
-   FFileMapping := FileMap;
 
-   // Offset must be a multiple of system memory allocation granularity
 
-   RoundToAllocGranularity64(ViewOffset, FFileMapping.RoundViewOffset = rvUp);
 
-   RoundToAllocGranularityPtr(Address, FFileMapping.RoundViewOffset = rvUp);
 
-   I64ToCardinals(ViewOffset, OffsetLow, OffsetHigh);
 
-   FOffsetHigh := OffsetHigh;
 
-   FOffsetLow := OffsetLow;
 
-   BaseAddress := MapViewOfFileEx(FFileMapping.Handle, Access, FOffsetHigh,
 
-     FOffsetLow, Size, Address);
 
-   if BaseAddress = nil then
 
-     raise EJclFileMappingViewError.CreateRes(@RsCreateFileMappingView);
 
-   // If we are mapping a file and size = 0 then MapViewOfFile has mapped the entire file. We must
 
-   // figure out the size ourselves before we can call SetPointer. Since in case of failure to
 
-   // retrieve the size we raise an exception, we also have to explicitly unmap the view which
 
-   // otherwise would have been done by the destructor.
 
-   if (Size = 0) and (FileMap is TJclFileMapping) then
 
-   begin
 
-     Size := GetFileSize(TJclFileMapping(FileMap).FFileHandle, nil);
 
-     if Size = DWORD(-1) then
 
-     begin
 
-       UnMapViewOfFile(BaseAddress);
 
-       raise EJclFileMappingViewError.CreateRes(@RsFailedToObtainSize);
 
-     end;
 
-   end;
 
-   SetPointer(BaseAddress, Size);
 
-   FFileMapping.FViews.Add(Self);
 
- end;
 
- destructor TJclFileMappingView.Destroy;
 
- var
 
-   IndexOfSelf: Integer;
 
- begin
 
-   if Memory <> nil then
 
-   begin
 
-     UnMapViewOfFile(Memory);
 
-     SetPointer(nil, 0);
 
-   end;
 
-   if FFileMapping <> nil then
 
-   begin
 
-     IndexOfSelf := FFileMapping.IndexOf(Self);
 
-     if IndexOfSelf <> -1 then
 
-       FFileMapping.FViews.Delete(IndexOfSelf);
 
-   end;
 
-   inherited Destroy;
 
- end;
 
- function TJclFileMappingView.Flush(const Count: Cardinal): Boolean;
 
- begin
 
-   Result := FlushViewOfFile(Memory, Count);
 
- end;
 
- function TJclFileMappingView.GetIndex: Integer;
 
- begin
 
-   Result := FFileMapping.IndexOf(Self);
 
- end;
 
- function TJclFileMappingView.GetOffset: Int64;
 
- begin
 
-   CardinalsToI64(Result, FOffsetLow, FOffsetHigh);
 
- end;
 
- procedure TJclFileMappingView.LoadFromFile(const FileName: string);
 
- var
 
-   Stream: TFileStream;
 
- begin
 
-   Stream := TFileStream.Create(Filename, fmOpenRead or fmShareDenyWrite);
 
-   try
 
-     LoadFromStream(Stream);
 
-   finally
 
-     FreeAndNil(Stream);
 
-   end;
 
- end;
 
- procedure TJclFileMappingView.LoadFromStream(const Stream: TStream);
 
- begin
 
-   if Stream.Size > Size then
 
-     raise EJclFileMappingViewError.CreateRes(@RsLoadFromStreamSize);
 
-   Stream.Position := 0;
 
-   Stream.ReadBuffer(Memory^, Stream.Size);
 
- end;
 
- function TJclFileMappingView.Write(const Buffer; Count: Integer): Longint;
 
- begin
 
-   Result := 0;
 
-   if (Size - Position) >= Count then
 
-   begin
 
-     System.Move(Buffer, Pointer(TJclAddr(Memory) + TJclAddr(Position))^, Count);
 
-     Position := Position + Count;
 
-     Result := Count;
 
-   end;
 
- end;
 
- //=== { TJclCustomFileMapping } ==============================================
 
- constructor TJclCustomFileMapping.Create;
 
- begin
 
-   inherited Create;
 
-   FViews := TList.Create;
 
-   FRoundViewOffset := rvDown;
 
- end;
 
- constructor TJclCustomFileMapping.Open(const Name: string;
 
-   const InheritHandle: Boolean; const DesiredAccess: Cardinal);
 
- begin
 
-   Create;
 
-   InternalOpen(Name, InheritHandle, DesiredAccess);
 
- end;
 
- destructor TJclCustomFileMapping.Destroy;
 
- begin
 
-   ClearViews;
 
-   if FHandle <> 0 then
 
-     CloseHandle(FHandle);
 
-   FreeAndNil(FViews);
 
-   inherited Destroy;
 
- end;
 
- function TJclCustomFileMapping.Add(const Access, Count: Cardinal; const Offset: Int64): Integer;
 
- var
 
-   View: TJclFileMappingView;
 
- begin
 
-   // The view adds itself to the FViews list
 
-   View := TJclFileMappingView.Create(Self, Access, Count, Offset);
 
-   Result := View.Index;
 
- end;
 
- function TJclCustomFileMapping.AddAt(const Access, Count: Cardinal;
 
-   const Offset: Int64; const Address: Pointer): Integer;
 
- var
 
-   View: TJclFileMappingView;
 
- begin
 
-   // The view adds itself to the FViews list
 
-   View := TJclFileMappingView.CreateAt(Self, Access, Count, Offset, Address);
 
-   Result := View.Index;
 
- end;
 
- procedure TJclCustomFileMapping.ClearViews;
 
- var
 
-   I: Integer;
 
- begin
 
-   // Note that the view destructor removes the view object from the FViews list so we must loop
 
-   // downwards from count to 0
 
-   for I := FViews.Count - 1 downto 0 do
 
-     TJclFileMappingView(FViews[I]).Free;
 
- end;
 
- procedure TJclCustomFileMapping.Delete(const Index: Integer);
 
- begin
 
-   // Note that the view destructor removes itself from FViews
 
-   TJclFileMappingView(FViews[Index]).Free;
 
- end;
 
- function TJclCustomFileMapping.GetCount: Integer;
 
- begin
 
-   Result := FViews.Count;
 
- end;
 
- function TJclCustomFileMapping.GetView(Index: Integer): TJclFileMappingView;
 
- begin
 
-   Result := TJclFileMappingView(FViews.Items[index]);
 
- end;
 
- function TJclCustomFileMapping.IndexOf(const View: TJclFileMappingView): Integer;
 
- begin
 
-   Result := FViews.IndexOf(View);
 
- end;
 
- procedure TJclCustomFileMapping.InternalCreate(const FileHandle: THandle;
 
-   const Name: string; const Protect: Cardinal; MaximumSize: Int64;
 
-   SecAttr: PSecurityAttributes);
 
- var
 
-   MaximumSizeLow, MaximumSizeHigh: Cardinal;
 
- begin
 
-   FName := Name;
 
-   I64ToCardinals(MaximumSize, MaximumSizeLow, MaximumSizeHigh);
 
-   FHandle := CreateFileMapping(FileHandle, SecAttr, Protect, MaximumSizeHigh,
 
-     MaximumSizeLow, PChar(Name));
 
-   if FHandle = 0 then
 
-     raise EJclFileMappingError.CreateRes(@RsCreateFileMapping);
 
-   FExisted := GetLastError = ERROR_ALREADY_EXISTS;
 
- end;
 
- procedure TJclCustomFileMapping.InternalOpen(const Name: string;
 
-   const InheritHandle: Boolean; const DesiredAccess: Cardinal);
 
- begin
 
-   FExisted := True;
 
-   FName := Name;
 
-   FHandle := OpenFileMapping(DesiredAccess, InheritHandle, PChar(Name));
 
-   if FHandle = 0 then
 
-     raise EJclFileMappingError.CreateRes(@RsCreateFileMapping);
 
- end;
 
- //=== { TJclFileMapping } ====================================================
 
- constructor TJclFileMapping.Create(const FileName: string; FileMode: Cardinal;
 
-   const Name: string; Protect: Cardinal; const MaximumSize: Int64;
 
-   SecAttr: PSecurityAttributes);
 
- begin
 
-   FFileHandle := INVALID_HANDLE_VALUE;
 
-   inherited Create;
 
-   FFileHandle := THandle(FileOpen(FileName, FileMode));
 
-   if FFileHandle = INVALID_HANDLE_VALUE then
 
-     raise EJclFileMappingError.CreateRes(@RsFileMappingOpenFile);
 
-   InternalCreate(FFileHandle, Name, Protect, MaximumSize, SecAttr);
 
- end;
 
- constructor TJclFileMapping.Create(const FileHandle: THandle; const Name: string;
 
-   Protect: Cardinal; const MaximumSize: Int64; SecAttr: PSecurityAttributes);
 
- begin
 
-   FFileHandle := INVALID_HANDLE_VALUE;
 
-   inherited Create;
 
-   if FileHandle = INVALID_HANDLE_VALUE then
 
-     raise EJclFileMappingError.CreateRes(@RsFileMappingInvalidHandle);
 
-   InternalCreate(FileHandle, Name, Protect, MaximumSize, SecAttr);
 
-   // Duplicate the handle into FFileHandle as opposed to assigning it directly. This will cause
 
-   // FFileHandle to retrieve a unique copy which is independent of FileHandle. This makes the
 
-   // remainder of the class, especially the destructor, easier. The caller will have to close it's
 
-   // own copy of the handle explicitly.
 
-   DuplicateHandle(GetCurrentProcess, FileHandle, GetCurrentProcess,
 
-     @FFileHandle, 0, False, DUPLICATE_SAME_ACCESS);
 
- end;
 
- destructor TJclFileMapping.Destroy;
 
- begin
 
-   if FFileHandle <> INVALID_HANDLE_VALUE then
 
-     CloseHandle(FFileHandle);
 
-   inherited Destroy;
 
- end;
 
- //=== { TJclSwapFileMapping } ================================================
 
- constructor TJclSwapFileMapping.Create(const Name: string; Protect: Cardinal;
 
-   const MaximumSize: Int64; SecAttr: PSecurityAttributes);
 
- begin
 
-   inherited Create;
 
-   InternalCreate(INVALID_HANDLE_VALUE, Name, Protect, MaximumSize, SecAttr);
 
- end;
 
- //=== { TJclFileMappingStream } ==============================================
 
- constructor TJclFileMappingStream.Create(const FileName: string; FileMode: Word);
 
- var
 
-   Protect, Access, Size: DWORD;
 
-   BaseAddress: Pointer;
 
- begin
 
-   inherited Create;
 
-   FFileHandle := THandle(FileOpen(FileName, FileMode));
 
-   if FFileHandle = INVALID_HANDLE_VALUE then
 
-     RaiseLastOSError;
 
-   if (FileMode and $0F) = fmOpenReadWrite then
 
-   begin
 
-     Protect := PAGE_WRITECOPY;
 
-     Access := FILE_MAP_COPY;
 
-   end
 
-   else
 
-   begin
 
-     Protect := PAGE_READONLY;
 
-     Access := FILE_MAP_READ;
 
-   end;
 
-   FMapping := CreateFileMapping(FFileHandle, nil, Protect, 0, 0, nil);
 
-   if FMapping = 0 then
 
-   begin
 
-     Close;
 
-     raise EJclFileMappingError.CreateRes(@RsCreateFileMapping);
 
-   end;
 
-   BaseAddress := MapViewOfFile(FMapping, Access, 0, 0, 0);
 
-   if BaseAddress = nil then
 
-   begin
 
-     Close;
 
-     raise EJclFileMappingViewError.CreateRes(@RsCreateFileMappingView);
 
-   end;
 
-   Size := GetFileSize(FFileHandle, nil);
 
-   if Size = DWORD(-1) then
 
-   begin
 
-     UnMapViewOfFile(BaseAddress);
 
-     Close;
 
-     raise EJclFileMappingViewError.CreateRes(@RsFailedToObtainSize);
 
-   end;
 
-   SetPointer(BaseAddress, Size);
 
- end;
 
- destructor TJclFileMappingStream.Destroy;
 
- begin
 
-   Close;
 
-   inherited Destroy;
 
- end;
 
- procedure TJclFileMappingStream.Close;
 
- begin
 
-   if Memory <> nil then
 
-   begin
 
-     UnMapViewOfFile(Memory);
 
-     SetPointer(nil, 0);
 
-   end;
 
-   if FMapping <> 0 then
 
-   begin
 
-     CloseHandle(FMapping);
 
-     FMapping := 0;
 
-   end;
 
-   if FFileHandle <> INVALID_HANDLE_VALUE then
 
-   begin
 
-     FileClose(FFileHandle);
 
-     FFileHandle := INVALID_HANDLE_VALUE;
 
-   end;
 
- end;
 
- function TJclFileMappingStream.Write(const Buffer; Count: Integer): Longint;
 
- begin
 
-   Result := 0;
 
-   if (Size - Position) >= Count then
 
-   begin
 
-     System.Move(Buffer, Pointer(TJclAddr(Memory) + TJclAddr(Position))^, Count);
 
-     Position := Position + Count;
 
-     Result := Count;
 
-   end;
 
- end;
 
- {$ENDIF MSWINDOWS}
 
- //=== { TJclAnsiMappedTextReader } ===========================================
 
- constructor TJclAnsiMappedTextReader.Create(MemoryStream: TCustomMemoryStream; FreeStream: Boolean;
 
-   const AIndexOption: TJclMappedTextReaderIndex);
 
- begin
 
-   inherited Create;
 
-   FMemoryStream := MemoryStream;
 
-   FFreeStream := FreeStream;
 
-   FIndexOption := AIndexOption;
 
-   Init;
 
- end;
 
- constructor TJclAnsiMappedTextReader.Create(const FileName: TFileName;
 
-   const AIndexOption: TJclMappedTextReaderIndex);
 
- begin
 
-   inherited Create;
 
-   {$IFDEF MSWINDOWS}
 
-   FMemoryStream := TJclFileMappingStream.Create(FileName);
 
-   {$ELSE ~ MSWINDOWS}
 
-   FMemoryStream := TMemoryStream.Create;
 
-   TMemoryStream(FMemoryStream).LoadFromFile(FileName);
 
-   {$ENDIF ~ MSWINDOWS}
 
-   FFreeStream := True;
 
-   FIndexOption := AIndexOption;
 
-   Init;
 
- end;
 
- destructor TJclAnsiMappedTextReader.Destroy;
 
- begin
 
-   if FFreeStream then
 
-     FMemoryStream.Free;
 
-   FreeMem(FIndex);
 
-   inherited Destroy;
 
- end;
 
- procedure TJclAnsiMappedTextReader.AssignTo(Dest: TPersistent);
 
- begin
 
-   if Dest is TStrings then
 
-   begin
 
-     GoBegin;
 
-     TStrings(Dest).BeginUpdate;
 
-     try
 
-       while not Eof do
 
-         TStrings(Dest).Add(string(ReadLn));
 
-     finally
 
-       TStrings(Dest).EndUpdate;
 
-     end;
 
-   end
 
-   else
 
-     inherited AssignTo(Dest);
 
- end;
 
- procedure TJclAnsiMappedTextReader.CreateIndex;
 
- var
 
-   P, LastLineStart: PAnsiChar;
 
-   I: Integer;
 
- begin
 
-   {$RANGECHECKS OFF}
 
-   P := FContent;
 
-   I := 0;
 
-   LastLineStart := P;
 
-   while P < FEnd do
 
-   begin
 
-     // CRLF, CR, LF and LFCR are seen as valid sets of chars for EOL marker
 
-     if CharIsReturn(Char(P^)) then
 
-     begin
 
-       if I and $FFFF = 0 then
 
-         ReallocMem(FIndex, (I + $10000) * SizeOf(Pointer));
 
-       FIndex[I] := LastLineStart;
 
-       Inc(I);
 
-       case P^ of
 
-         NativeLineFeed:
 
-           begin
 
-             Inc(P);
 
-             if (P < FEnd) and (P^ = NativeCarriageReturn) then
 
-              Inc(P);
 
-           end;
 
-         NativeCarriageReturn:
 
-           begin
 
-             Inc(P);
 
-             if (P < FEnd) and (P^ = NativeLineFeed) then
 
-               Inc(P);
 
-           end;
 
-       end;
 
-       LastLineStart := P;
 
-     end
 
-     else
 
-       Inc(P);
 
-   end;
 
-   if P > LastLineStart then
 
-   begin
 
-     ReallocMem(FIndex, (I + 1) * SizeOf(Pointer));
 
-     FIndex[I] := LastLineStart;
 
-     Inc(I);
 
-   end
 
-   else
 
-     ReallocMem(FIndex, I * SizeOf(Pointer));
 
-   FLineCount := I;
 
-   {$IFDEF RANGECHECKS_ON}
 
-   {$RANGECHECKS ON}
 
-   {$ENDIF RANGECHECKS_ON}
 
- end;
 
- function TJclAnsiMappedTextReader.GetEof: Boolean;
 
- begin
 
-   Result := FPosition >= FEnd;
 
- end;
 
- function TJclAnsiMappedTextReader.GetAsString: AnsiString;
 
- begin
 
-   SetString(Result, Content, Size);
 
- end;
 
- function TJclAnsiMappedTextReader.GetChars(Index: Integer): AnsiChar;
 
- begin
 
-   if (Index < 0) or (Index >= Size) then
 
-     raise EJclError.CreateRes(@RsFileIndexOutOfRange);
 
-   Result := AnsiChar(PByte(FContent + Index)^);
 
- end;
 
- function TJclAnsiMappedTextReader.GetLineCount: Integer;
 
- var
 
-   P: PAnsiChar;
 
- begin
 
-   if FLineCount = -1 then
 
-   begin
 
-     FLineCount := 0;
 
-     if FContent < FEnd then
 
-     begin
 
-       P := FContent;
 
-       while P < FEnd do
 
-       begin
 
-         case P^ of
 
-           NativeLineFeed:
 
-             begin
 
-               Inc(FLineCount);
 
-               Inc(P);
 
-               if (P < FEnd) and (P^ = NativeCarriageReturn) then
 
-                 Inc(P);
 
-             end;
 
-           NativeCarriageReturn:
 
-             begin
 
-               Inc(FLineCount);
 
-               Inc(P);
 
-               if (P < FEnd) and (P^ = NativeLineFeed) then
 
-                 Inc(P);
 
-             end;
 
-         else
 
-           Inc(P);
 
-         end;
 
-       end;
 
-       if (P = FEnd) and (P > FContent) and not CharIsReturn(Char((P-1)^)) then
 
-         Inc(FLineCount);
 
-     end;
 
-   end;
 
-   Result := FLineCount;
 
- end;
 
- function TJclAnsiMappedTextReader.GetLines(LineNumber: Integer): AnsiString;
 
- var
 
-   P: PAnsiChar;
 
- begin
 
-   P := PtrFromLine(LineNumber);
 
-   Result := StringFromPosition(P);
 
- end;
 
- function TJclAnsiMappedTextReader.GetPosition: Integer;
 
- begin
 
-   Result := FPosition - FContent;
 
- end;
 
- procedure TJclAnsiMappedTextReader.GoBegin;
 
- begin
 
-   Position := 0;
 
- end;
 
- procedure TJclAnsiMappedTextReader.Init;
 
- begin
 
-   FContent := FMemoryStream.Memory;
 
-   FSize := FMemoryStream.Size;
 
-   FEnd := FContent + FSize;
 
-   FPosition := FContent;
 
-   FLineCount := -1;
 
-   FLastLineNumber := 0;
 
-   FLastPosition := FContent;
 
-   if IndexOption = tiFull then
 
-     CreateIndex;
 
- end;
 
- function TJclAnsiMappedTextReader.GetPositionFromLine(LineNumber: Integer): Integer;
 
- var
 
-   P: PAnsiChar;
 
- begin
 
-   P := PtrFromLine(LineNumber);
 
-   if P = nil then
 
-     Result := -1
 
-   else
 
-     Result := P - FContent;
 
- end;
 
- function TJclAnsiMappedTextReader.PtrFromLine(LineNumber: Integer): PAnsiChar;
 
- var
 
-   LineOffset: Integer;
 
- begin
 
-   Result := nil;
 
-   {$RANGECHECKS OFF}
 
-   if (IndexOption <> tiNoIndex) and (LineNumber < FLineCount) and (FIndex[LineNumber] <> nil) then
 
-     Result := FIndex[LineNumber]
 
-   {$IFDEF RANGECHECKS_ON}
 
-   {$RANGECHECKS ON}
 
-   {$ENDIF RANGECHECKS_ON}
 
-   else
 
-   begin
 
-     LineOffset := LineNumber - FLastLineNumber;
 
-     if (FLineCount <> -1) and (LineNumber > 0) then
 
-     begin
 
-       if -LineOffset > LineNumber then
 
-       begin
 
-         FLastLineNumber := 0;
 
-         FLastPosition := FContent;
 
-         LineOffset := LineNumber;
 
-       end
 
-       else
 
-       if LineOffset > FLineCount - LineNumber then
 
-       begin
 
-         FLastLineNumber := FLineCount;
 
-         FLastPosition := FEnd;
 
-         LineOffset := LineNumber - FLineCount;
 
-       end;
 
-     end;
 
-     if LineNumber <= 0 then
 
-       Result := FContent
 
-     else
 
-     if LineOffset = 0 then
 
-       Result := FLastPosition
 
-     else
 
-     if LineOffset > 0 then
 
-     begin
 
-       Result := FLastPosition;
 
-       while (Result < FEnd) and (LineOffset > 0) do
 
-       begin
 
-         case Result^ of
 
-           NativeLineFeed:
 
-             begin
 
-               Dec(LineOffset);
 
-               Inc(Result);
 
-               if (Result < FEnd) and (Result^ = NativeCarriageReturn) then
 
-                 Inc(Result);
 
-             end;
 
-           NativeCarriageReturn:
 
-             begin
 
-               Dec(LineOffset);
 
-               Inc(Result);
 
-               if (Result < FEnd) and (Result^ = NativeLineFeed) then
 
-                 Inc(Result);
 
-             end;
 
-         else
 
-           Inc(Result);
 
-         end;
 
-       end;
 
-     end
 
-     else
 
-     if LineOffset < 0 then
 
-     begin
 
-       Result := FLastPosition;
 
-       while (Result > FContent) and (LineOffset < 1) do
 
-       begin
 
-         Dec(Result);
 
-         case Result^ of
 
-           NativeLineFeed:
 
-             begin
 
-               Inc(LineOffset);
 
-               if LineOffset >= 1 then
 
-                 Inc(Result)
 
-               else
 
-               if (Result > FContent) and ((Result-1)^ = NativeCarriageReturn) then
 
-                 Dec(Result);
 
-             end;
 
-           NativeCarriageReturn:
 
-             begin
 
-               Inc(LineOffset);
 
-               if LineOffset >= 1 then
 
-                 Inc(Result)
 
-               else
 
-               if (Result > FContent) and ((Result-1)^ = NativeLineFeed) then
 
-                 Dec(Result);
 
-             end;
 
-         end;
 
-       end;
 
-     end;
 
-     FLastLineNumber := LineNumber;
 
-     FLastPosition := Result;
 
-   end;
 
- end;
 
- function TJclAnsiMappedTextReader.Read: AnsiChar;
 
- begin
 
-   if FPosition >= FEnd then
 
-     Result := #0
 
-   else
 
-   begin
 
-     Result := FPosition^;
 
-     Inc(FPosition);
 
-   end;
 
- end;
 
- function TJclAnsiMappedTextReader.ReadLn: AnsiString;
 
- begin
 
-   Result := StringFromPosition(FPosition);
 
- end;
 
- procedure TJclAnsiMappedTextReader.SetPosition(const Value: Integer);
 
- begin
 
-   FPosition := FContent + Value;
 
- end;
 
- function TJclAnsiMappedTextReader.StringFromPosition(var StartPos: PAnsiChar): AnsiString;
 
- var
 
-   P: PAnsiChar;
 
- begin
 
-   if (StartPos = nil) or (StartPos >= FEnd) then
 
-     Result := ''
 
-   else
 
-   begin
 
-     P := StartPos;
 
-     while (P < FEnd) and (not CharIsReturn(Char(P^))) do
 
-       Inc(P);
 
-     SetString(Result, StartPos, P - StartPos);
 
-     if P < FEnd then
 
-     begin
 
-       case P^ of
 
-         NativeLineFeed:
 
-           begin
 
-             Inc(P);
 
-             if (P < FEnd) and (P^ = NativeCarriageReturn) then
 
-               Inc(P);
 
-           end;
 
-         NativeCarriageReturn:
 
-           begin
 
-             Inc(P);
 
-             if (P < FEnd) and (P^ = NativeLineFeed) then
 
-               Inc(P);
 
-           end;
 
-       end;
 
-     end;
 
-     StartPos := P;
 
-   end;
 
- end;
 
- //=== { TJclWideMappedTextReader } ===========================================
 
- constructor TJclWideMappedTextReader.Create(MemoryStream: TCustomMemoryStream; FreeStream: Boolean;
 
-   const AIndexOption: TJclMappedTextReaderIndex);
 
- begin
 
-   inherited Create;
 
-   FMemoryStream := MemoryStream;
 
-   FFreeStream := FreeStream;
 
-   FIndexOption := AIndexOption;
 
-   Init;
 
- end;
 
- constructor TJclWideMappedTextReader.Create(const FileName: TFileName;
 
-   const AIndexOption: TJclMappedTextReaderIndex);
 
- begin
 
-   inherited Create;
 
-   {$IFDEF MSWINDOWS}
 
-   FMemoryStream := TJclFileMappingStream.Create(FileName);
 
-   {$ELSE ~ MSWINDOWS}
 
-   FMemoryStream := TMemoryStream.Create;
 
-   TMemoryStream(FMemoryStream).LoadFromFile(FileName);
 
-   {$ENDIF ~ MSWINDOWS}
 
-   FFreeStream := True;
 
-   FIndexOption := AIndexOption;
 
-   Init;
 
- end;
 
- destructor TJclWideMappedTextReader.Destroy;
 
- begin
 
-   if FFreeStream then
 
-     FMemoryStream.Free;
 
-   FreeMem(FIndex);
 
-   inherited Destroy;
 
- end;
 
- procedure TJclWideMappedTextReader.AssignTo(Dest: TPersistent);
 
- begin
 
-   if Dest is TStrings then
 
-   begin
 
-     GoBegin;
 
-     TStrings(Dest).BeginUpdate;
 
-     try
 
-       while not Eof do
 
-         TStrings(Dest).Add(string(ReadLn));
 
-     finally
 
-       TStrings(Dest).EndUpdate;
 
-     end;
 
-   end
 
-   else
 
-     inherited AssignTo(Dest);
 
- end;
 
- procedure TJclWideMappedTextReader.CreateIndex;
 
- var
 
-   P, LastLineStart: PWideChar;
 
-   I: Integer;
 
- begin
 
-   {$RANGECHECKS OFF}
 
-   P := FContent;
 
-   I := 0;
 
-   LastLineStart := P;
 
-   while P < FEnd do
 
-   begin
 
-     // CRLF, CR, LF and LFCR are seen as valid sets of chars for EOL marker
 
-     if CharIsReturn(Char(P^)) then
 
-     begin
 
-       if I and $FFFF = 0 then
 
-         ReallocMem(FIndex, (I + $10000) * SizeOf(Pointer));
 
-       FIndex[I] := LastLineStart;
 
-       Inc(I);
 
-       case P^ of
 
-         NativeLineFeed:
 
-           begin
 
-             Inc(P);
 
-             if (P < FEnd) and (P^ = NativeCarriageReturn) then
 
-              Inc(P);
 
-           end;
 
-         NativeCarriageReturn:
 
-           begin
 
-             Inc(P);
 
-             if (P < FEnd) and (P^ = NativeLineFeed) then
 
-               Inc(P);
 
-           end;
 
-       end;
 
-       LastLineStart := P;
 
-     end
 
-     else
 
-       Inc(P);
 
-   end;
 
-   if P > LastLineStart then
 
-   begin
 
-     ReallocMem(FIndex, (I + 1) * SizeOf(Pointer));
 
-     FIndex[I] := LastLineStart;
 
-     Inc(I);
 
-   end
 
-   else
 
-     ReallocMem(FIndex, I * SizeOf(Pointer));
 
-   FLineCount := I;
 
-   {$IFDEF RANGECHECKS_ON}
 
-   {$RANGECHECKS ON}
 
-   {$ENDIF RANGECHECKS_ON}
 
- end;
 
- function TJclWideMappedTextReader.GetEof: Boolean;
 
- begin
 
-   Result := FPosition >= FEnd;
 
- end;
 
- function TJclWideMappedTextReader.GetAsString: WideString;
 
- begin
 
-   SetString(Result, Content, Size);
 
- end;
 
- function TJclWideMappedTextReader.GetChars(Index: Integer): WideChar;
 
- begin
 
-   if (Index < 0) or (Index >= Size) then
 
-     raise EJclError.CreateRes(@RsFileIndexOutOfRange);
 
-   Result := WideChar(PByte(FContent + Index)^);
 
- end;
 
- function TJclWideMappedTextReader.GetLineCount: Integer;
 
- var
 
-   P: PWideChar;
 
- begin
 
-   if FLineCount = -1 then
 
-   begin
 
-     FLineCount := 0;
 
-     if FContent < FEnd then
 
-     begin
 
-       P := FContent;
 
-       while P < FEnd do
 
-       begin
 
-         case P^ of
 
-           NativeLineFeed:
 
-             begin
 
-               Inc(FLineCount);
 
-               Inc(P);
 
-               if (P < FEnd) and (P^ = NativeCarriageReturn) then
 
-                 Inc(P);
 
-             end;
 
-           NativeCarriageReturn:
 
-             begin
 
-               Inc(FLineCount);
 
-               Inc(P);
 
-               if (P < FEnd) and (P^ = NativeLineFeed) then
 
-                 Inc(P);
 
-             end;
 
-         else
 
-           Inc(P);
 
-         end;
 
-       end;
 
-       if (P = FEnd) and (P > FContent) and not CharIsReturn(Char((P-1)^)) then
 
-         Inc(FLineCount);
 
-     end;
 
-   end;
 
-   Result := FLineCount;
 
- end;
 
- function TJclWideMappedTextReader.GetLines(LineNumber: Integer): WideString;
 
- var
 
-   P: PWideChar;
 
- begin
 
-   P := PtrFromLine(LineNumber);
 
-   Result := StringFromPosition(P);
 
- end;
 
- function TJclWideMappedTextReader.GetPosition: Integer;
 
- begin
 
-   Result := FPosition - FContent;
 
- end;
 
- procedure TJclWideMappedTextReader.GoBegin;
 
- begin
 
-   Position := 0;
 
- end;
 
- procedure TJclWideMappedTextReader.Init;
 
- begin
 
-   FContent := FMemoryStream.Memory;
 
-   FSize := FMemoryStream.Size;
 
-   FEnd := FContent + FSize;
 
-   FPosition := FContent;
 
-   FLineCount := -1;
 
-   FLastLineNumber := 0;
 
-   FLastPosition := FContent;
 
-   if IndexOption = tiFull then
 
-     CreateIndex;
 
- end;
 
- function TJclWideMappedTextReader.GetPositionFromLine(LineNumber: Integer): Integer;
 
- var
 
-   P: PWideChar;
 
- begin
 
-   P := PtrFromLine(LineNumber);
 
-   if P = nil then
 
-     Result := -1
 
-   else
 
-     Result := P - FContent;
 
- end;
 
- function TJclWideMappedTextReader.PtrFromLine(LineNumber: Integer): PWideChar;
 
- var
 
-   LineOffset: Integer;
 
- begin
 
-   Result := nil;
 
-   {$RANGECHECKS OFF}
 
-   if (IndexOption <> tiNoIndex) and (LineNumber < FLineCount) and (FIndex[LineNumber] <> nil) then
 
-     Result := FIndex[LineNumber]
 
-   {$IFDEF RANGECHECKS_ON}
 
-   {$RANGECHECKS ON}
 
-   {$ENDIF RANGECHECKS_ON}
 
-   else
 
-   begin
 
-     LineOffset := LineNumber - FLastLineNumber;
 
-     if (FLineCount <> -1) and (LineNumber > 0) then
 
-     begin
 
-       if -LineOffset > LineNumber then
 
-       begin
 
-         FLastLineNumber := 0;
 
-         FLastPosition := FContent;
 
-         LineOffset := LineNumber;
 
-       end
 
-       else
 
-       if LineOffset > FLineCount - LineNumber then
 
-       begin
 
-         FLastLineNumber := FLineCount;
 
-         FLastPosition := FEnd;
 
-         LineOffset := LineNumber - FLineCount;
 
-       end;
 
-     end;
 
-     if LineNumber <= 0 then
 
-       Result := FContent
 
-     else
 
-     if LineOffset = 0 then
 
-       Result := FLastPosition
 
-     else
 
-     if LineOffset > 0 then
 
-     begin
 
-       Result := FLastPosition;
 
-       while (Result < FEnd) and (LineOffset > 0) do
 
-       begin
 
-         case Result^ of
 
-           NativeLineFeed:
 
-             begin
 
-               Dec(LineOffset);
 
-               Inc(Result);
 
-               if (Result < FEnd) and (Result^ = NativeCarriageReturn) then
 
-                 Inc(Result);
 
-             end;
 
-           NativeCarriageReturn:
 
-             begin
 
-               Dec(LineOffset);
 
-               Inc(Result);
 
-               if (Result < FEnd) and (Result^ = NativeLineFeed) then
 
-                 Inc(Result);
 
-             end;
 
-         else
 
-           Inc(Result);
 
-         end;
 
-       end;
 
-     end
 
-     else
 
-     if LineOffset < 0 then
 
-     begin
 
-       Result := FLastPosition;
 
-       while (Result > FContent) and (LineOffset < 1) do
 
-       begin
 
-         Dec(Result);
 
-         case Result^ of
 
-           NativeLineFeed:
 
-             begin
 
-               Inc(LineOffset);
 
-               if LineOffset >= 1 then
 
-                 Inc(Result)
 
-               else
 
-               if (Result > FContent) and ((Result-1)^ = NativeCarriageReturn) then
 
-                 Dec(Result);
 
-             end;
 
-           NativeCarriageReturn:
 
-             begin
 
-               Inc(LineOffset);
 
-               if LineOffset >= 1 then
 
-                 Inc(Result)
 
-               else
 
-               if (Result > FContent) and ((Result-1)^ = NativeLineFeed) then
 
-                 Dec(Result);
 
-             end;
 
-         end;
 
-       end;
 
-     end;
 
-     FLastLineNumber := LineNumber;
 
-     FLastPosition := Result;
 
-   end;
 
- end;
 
- function TJclWideMappedTextReader.Read: WideChar;
 
- begin
 
-   if FPosition >= FEnd then
 
-     Result := #0
 
-   else
 
-   begin
 
-     Result := FPosition^;
 
-     Inc(FPosition);
 
-   end;
 
- end;
 
- function TJclWideMappedTextReader.ReadLn: WideString;
 
- begin
 
-   Result := StringFromPosition(FPosition);
 
- end;
 
- procedure TJclWideMappedTextReader.SetPosition(const Value: Integer);
 
- begin
 
-   FPosition := FContent + Value;
 
- end;
 
- function TJclWideMappedTextReader.StringFromPosition(var StartPos: PWideChar): WideString;
 
- var
 
-   P: PWideChar;
 
- begin
 
-   if (StartPos = nil) or (StartPos >= FEnd) then
 
-     Result := ''
 
-   else
 
-   begin
 
-     P := StartPos;
 
-     while (P < FEnd) and (not CharIsReturn(Char(P^))) do
 
-       Inc(P);
 
-     SetString(Result, StartPos, P - StartPos);
 
-     if P < FEnd then
 
-     begin
 
-       case P^ of
 
-         NativeLineFeed:
 
-           begin
 
-             Inc(P);
 
-             if (P < FEnd) and (P^ = NativeCarriageReturn) then
 
-               Inc(P);
 
-           end;
 
-         NativeCarriageReturn:
 
-           begin
 
-             Inc(P);
 
-             if (P < FEnd) and (P^ = NativeLineFeed) then
 
-               Inc(P);
 
-           end;
 
-       end;
 
-     end;
 
-     StartPos := P;
 
-   end;
 
- end;
 
- function CharIsDriveLetter(const C: Char): Boolean;
 
- begin
 
-   case C of
 
-     'a'..'z',
 
-     'A'..'Z':
 
-       Result := True;
 
-   else
 
-     Result := False;
 
-   end;
 
- end;
 
- //=== Path manipulation ======================================================
 
- function PathAddSeparator(const Path: string): string;
 
- begin
 
-   Result := Path;
 
-   if (Path = '') or (Path[Length(Path)] <> DirDelimiter) then
 
-     Result := Path + DirDelimiter;
 
- end;
 
- function PathAddExtension(const Path, Extension: string): string;
 
- begin
 
-   Result := Path;
 
-   // (obones) Extension may not contain the leading dot while ExtractFileExt
 
-   // always returns it. Hence the need to use StrEnsurePrefix for the SameText
 
-   // test to return an accurate value.
 
-   if (Path <> '') and (Extension <> '') and
 
-     not SameText(ExtractFileExt(Path), StrEnsurePrefix('.', Extension)) then
 
-   begin
 
-     if Path[Length(Path)] = '.' then
 
-       Delete(Result, Length(Path), 1);
 
-     if Extension[1] = '.' then
 
-       Result := Result + Extension
 
-     else
 
-       Result := Result + '.' + Extension;
 
-   end;
 
- end;
 
- function PathAppend(const Path, Append: string): string;
 
- var
 
-   PathLength: Integer;
 
-   B1, B2: Boolean;
 
- begin
 
-   if Append = '' then
 
-     Result := Path
 
-   else
 
-   begin
 
-     PathLength := Length(Path);
 
-     if PathLength = 0 then
 
-       Result := Append
 
-     else
 
-     begin
 
-       // The following code may look a bit complex but all it does is add Append to Path ensuring
 
-       // that there is one and only one path separator character between them
 
-       B1 := Path[PathLength] = DirDelimiter;
 
-       B2 := Append[1] = DirDelimiter;
 
-       if B1 and B2 then
 
-         Result := Copy(Path, 1, PathLength - 1) + Append
 
-       else
 
-       begin
 
-         if not (B1 or B2) then
 
-           Result := Path + DirDelimiter + Append
 
-         else
 
-           Result := Path + Append;
 
-       end;
 
-     end;
 
-   end;
 
- end;
 
- function PathBuildRoot(const Drive: Byte): string;
 
- begin
 
-   {$IFDEF UNIX}
 
-   Result := DirDelimiter;
 
-   {$ENDIF UNIX}
 
-   {$IFDEF MSWINDOWS}
 
-   // Remember, Win32 only allows 'a' to 'z' as drive letters (mapped to 0..25)
 
-   if Drive < 26 then
 
-     Result := Char(Drive + 65) + ':\'
 
-   else
 
-     raise EJclPathError.CreateResFmt(@RsPathInvalidDrive, [IntToStr(Drive)]);
 
-   {$ENDIF MSWINDOWS}
 
- end;
 
- function PathCanonicalize(const Path: string): string;
 
- var
 
-   List: TStringList;
 
-   S: string;
 
-   I, K: Integer;
 
-   IsAbsolute: Boolean;
 
- begin
 
-   I := Pos(':', Path); // for Windows' sake
 
-   K := Pos(DirDelimiter, Path);
 
-   IsAbsolute := K - I = 1;
 
-   if IsAbsolute then begin
 
-     if Copy(Path, 1, Length(PathUncPrefix)) = PathUncPrefix then // UNC path
 
-       K := 2;
 
-   end else
 
-     K := I;
 
-   if K = 0 then
 
-     S := Path
 
-   else
 
-     S := Copy(Path, K + 1, Length(Path));
 
-   List := TStringList.Create;
 
-   try
 
-     StrIToStrings(S, DirDelimiter, List, True);
 
-     I := 0;
 
-     while I < List.Count do
 
-     begin
 
-       if List[I] = '.' then
 
-         List.Delete(I)
 
-       else
 
-       if (IsAbsolute or (I > 0) and not (List[I-1] = '..')) and (List[I] = '..') then
 
-       begin
 
-         List.Delete(I);
 
-         if I > 0 then
 
-         begin
 
-           Dec(I);
 
-           List.Delete(I);
 
-         end;
 
-       end
 
-       else Inc(I);
 
-     end;
 
-     Result := StringsToStr(List, DirDelimiter, True);
 
-   finally
 
-     List.Free;
 
-   end;
 
-   if K > 0 then
 
-     Result := Copy(Path, 1, K) + Result
 
-   else
 
-   if Result = '' then
 
-     Result := '.';
 
- end;
 
- function PathCommonPrefix(const Path1, Path2: string): Integer;
 
- var
 
-   Index1, Index2: Integer;
 
-   LastSeparator, LenS1: Integer;
 
-   S1, S2: string;
 
- begin
 
-   Result := 0;
 
-   if (Path1 <> '') and (Path2 <> '') then
 
-   begin
 
-     // Initialize P1 to the shortest of the two paths so that the actual comparison loop below can
 
-     // use the terminating #0 of that string to terminate the loop.
 
-     if Length(Path1) <= Length(Path2) then
 
-     begin
 
-       S1 := Path1;
 
-       S2 := Path2;
 
-     end
 
-     else
 
-     begin
 
-       S1 := Path2;
 
-       S2 := Path1;
 
-     end;
 
-     Index1 := 1;
 
-     Index2 := 1;
 
-     LenS1 := Length(S1);
 
-     LastSeparator := 0;
 
-     while (S1[Index1] = S2[Index2]) and (Index1 <= LenS1) do
 
-     begin
 
-       Inc(Result);
 
-       if (S1[Index1] = DirDelimiter) or (S1[Index1] = ':') then
 
-         LastSeparator := Result;
 
-       Inc(Index1);
 
-       Inc(Index2);
 
-     end;
 
-     if (LastSeparator < Result) and (Index1 <= LenS1) then
 
-       Result := LastSeparator;
 
-   end;
 
- end;
 
- {$IFDEF MSWINDOWS}
 
- function PathCompactPath(const DC: HDC; const Path: string;
 
-   const Width: Integer; CmpFmt: TCompactPath): string;
 
- const
 
-   Compacts: array [TCompactPath] of Cardinal = (DT_PATH_ELLIPSIS, DT_END_ELLIPSIS);
 
- var
 
-   TextRect: TRect;
 
-   Fmt: Cardinal;
 
- begin
 
-   Result := '';
 
-   if (DC <> 0) and (Path <> '') and (Width > 0) then
 
-   begin
 
-     { Here's a note from the Platform SDK to explain the + 5 in the call below:
 
-     "If dwDTFormat includes DT_MODIFYSTRING, the function could add up to four additional characters
 
-     to this string. The buffer containing the string should be large enough to accommodate these
 
-     extra characters." }
 
-     SetString(Result, PChar(Path), Length(Path) + 4);
 
-     TextRect := Rect(0, 0, Width, 255);
 
-     Fmt := DT_MODIFYSTRING or DT_CALCRECT or Compacts[CmpFmt];
 
-     if DrawTextEx(DC, PChar(Result), -1, TextRect, Fmt, nil) <> 0 then
 
-       StrResetLength(Result)
 
-     else
 
-       Result := '';  // in case of error
 
-   end;
 
- end;
 
- {$ENDIF MSWINDOWS}
 
- procedure PathExtractElements(const Source: string; var Drive, Path, FileName, Ext: string);
 
- begin
 
-   Drive := ExtractFileDrive(Source);
 
-   Path := ExtractFilePath(Source);
 
-   // Path includes drive so remove that
 
-   if Drive <> '' then
 
-     Delete(Path, 1, Length(Drive));
 
-   // add/remove separators
 
-   Drive := PathAddSeparator(Drive);
 
-   Path := PathRemoveSeparator(Path);
 
-   if (Path <> '') and (Path[1] = DirDelimiter) then
 
-     Delete(Path, 1, 1);
 
-   // and extract the remaining elements
 
-   FileName := PathExtractFileNameNoExt(Source);
 
-   Ext := ExtractFileExt(Source);
 
- end;
 
- function PathExtractFileDirFixed(const S: string): string;
 
- begin
 
-   Result := PathAddSeparator(ExtractFileDir(S));
 
- end;
 
- function PathExtractFileNameNoExt(const Path: string): string;
 
- begin
 
-   Result := PathRemoveExtension(ExtractFileName(Path));
 
- end;
 
- function PathExtractPathDepth(const Path: string; Depth: Integer): string;
 
- var
 
-   List: TStringList;
 
-   LocalPath: string;
 
-   I: Integer;
 
- begin
 
-   List := TStringList.Create;
 
-   try
 
-     if IsDirectory(Path) then
 
-       LocalPath := Path
 
-     else
 
-       LocalPath := ExtractFilePath(Path);
 
-     StrIToStrings(LocalPath, DirDelimiter, List, True);
 
-     I := Depth + 1;
 
-     if PathIsUNC(LocalPath) then
 
-       I := I + 2;
 
-     while I < List.Count do
 
-       List.Delete(I);
 
-     Result := PathAddSeparator(StringsToStr(List, DirDelimiter, True));
 
-   finally
 
-     List.Free;
 
-   end;
 
- end;
 
- //  Notes: maybe this function should first apply PathCanonicalize() ?
 
- function PathGetDepth(const Path: string): Integer;
 
- var
 
-   List: TStringList;
 
-   LocalPath: string;
 
-   I, Start: Integer;
 
- begin
 
-   Result := 0;
 
-   List := TStringList.Create;
 
-   try
 
-     if IsDirectory(Path) then
 
-       LocalPath := Path
 
-     else
 
-       LocalPath := ExtractFilePath(Path);
 
-     StrIToStrings(LocalPath, DirDelimiter, List, False);
 
-     if PathIsUNC(LocalPath) then
 
-       Start := 1
 
-     else
 
-       Start := 0;
 
-     for I := Start to List.Count - 1 do
 
-     begin
 
-       if Pos(':', List[I]) = 0 then
 
-         Inc(Result);
 
-     end;
 
-   finally
 
-     List.Free;
 
-   end;
 
- end;
 
- {$IFDEF MSWINDOWS}
 
- function ShellGetLongPathName(const Path: string): string;
 
- {$IFDEF FPC}
 
- // As of 2004-10-17, FPC's ShlObj unit is just a dummy
 
- begin
 
-   Result := Path;
 
- end;
 
- {$ElSE ~FPC}
 
- var
 
-   PIDL: PItemIDList;
 
-   Desktop: IShellFolder;
 
-   {$IFNDEF SUPPORTS_UNICODE}
 
-   AnsiName: string;
 
-   WideName: array [0..MAX_PATH] of WideChar;
 
-   {$ENDIF ~SUPPORTS_UNICODE}
 
-   Eaten, Attr: ULONG; // both unused but API requires them (incorrect translation)
 
- begin
 
-   Result := Path;
 
-   if Path <> '' then
 
-   begin
 
-     if Succeeded(SHGetDesktopFolder(Desktop)) then
 
-     begin
 
-       {$IFDEF SUPPORTS_UNICODE}
 
-       if Succeeded(Desktop.ParseDisplayName(0, nil, PChar(Path), Eaten, PIDL, Attr)) then
 
-       try
 
-         SetLength(Result, MAX_PATH);
 
-         if SHGetPathFromIDList(PIDL, PChar(Result)) then
 
-           StrResetLength(Result);
 
-       finally
 
-         CoTaskMemFree(PIDL);
 
-       end;
 
-       {$ELSE ~SUPPORTS_UNICODE}
 
-       MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, PAnsiChar(Path), -1, WideName, MAX_PATH);
 
-       if Succeeded(Desktop.ParseDisplayName(0, nil, WideName, Eaten, PIDL, Attr)) then
 
-       try
 
-         SetLength(AnsiName, MAX_PATH);
 
-         if SHGetPathFromIDList(PIDL, PChar(AnsiName)) then
 
-           StrResetLength(AnsiName);
 
-         Result := AnsiName;
 
-       finally
 
-         CoTaskMemFree(PIDL);
 
-       end;
 
-       {$ENDIF ~SUPPORTS_UNICODE}
 
-     end;
 
-   end;
 
- end;
 
- {$ENDIF ~FPC}
 
- { TODO : Move RTDL code over to JclWin32 when JclWin32 gets overhauled. }
 
- var
 
-   _Kernel32Handle: TModuleHandle = INVALID_MODULEHANDLE_VALUE;
 
-   _GetLongPathName: function (lpszShortPath: PChar; lpszLongPath: PChar;
 
-     cchBuffer: DWORD): DWORD; stdcall;
 
- function Kernel32Handle: HMODULE;
 
- begin
 
-   JclSysUtils.LoadModule(_Kernel32Handle, kernel32);
 
-   Result := _Kernel32Handle;
 
- end;
 
- function RtdlGetLongPathName(const Path: string): string;
 
- begin
 
-   Result := Path;
 
-   if not Assigned(_GetLongPathName) then
 
-     _GetLongPathName := GetModuleSymbol(Kernel32Handle, 'GetLongPathName' + AWSuffix);
 
-   if not Assigned(_GetLongPathName) then
 
-     Result := ShellGetLongPathName(Path)
 
-   else
 
-   begin
 
-     SetLength(Result, MAX_PATH);
 
-     SetLength(Result, _GetLongPathName(PChar(Path), PChar(Result), MAX_PATH));
 
-   end;
 
- end;
 
- function PathGetLongName(const Path: string): string;
 
- begin
 
-   if Pos('::', Path) > 0 then // Path contains '::{<GUID>}'
 
-     Result := ShellGetLongPathName(Path)
 
-   else
 
-     Result := RtdlGetLongPathName(Path);
 
-   if Result = '' then
 
-     Result := Path;
 
- end;
 
- function PathGetShortName(const Path: string): string;
 
- var
 
-   Required: Integer;
 
- begin
 
-   Result := Path;
 
-   Required := GetShortPathName(PChar(Path), nil, 0);
 
-   if Required <> 0 then
 
-   begin
 
-     SetLength(Result, Required);
 
-     Required := GetShortPathName(PChar(Path), PChar(Result), Required);
 
-     if (Required <> 0) and (Required = Length(Result) - 1) then
 
-       SetLength(Result, Required)
 
-     else
 
-       Result := Path;
 
-   end;
 
- end;
 
- {$ENDIF MSWINDOWS}
 
- function PathGetRelativePath(Origin, Destination: string): string;
 
- var
 
-   {$IFDEF MSWINDOWS}
 
-   OrigDrive: string;
 
-   DestDrive: string;
 
-   {$ENDIF MSWINDOWS}
 
-   OrigList: TStringList;
 
-   DestList: TStringList;
 
-   DiffIndex: Integer;
 
-   I: Integer;
 
-   function StartsFromRoot(const Path: string): Boolean;
 
-  {$IFDEF MSWINDOWS}
 
-   var
 
-     I: Integer;
 
-   begin
 
-     I := Length(ExtractFileDrive(Path));
 
-     Result := (Length(Path) > I) and (Path[I + 1] = DirDelimiter);
 
-   end;
 
-   {$ELSE ~MSWINDOWS}
 
-   begin
 
-     Result := Pos(DirDelimiter, Path) = 1;
 
-   end;
 
-   {$ENDIF ~MSWINDOWS}
 
-   function Equal(const Path1, Path2: string): Boolean;
 
-   begin
 
-     {$IFDEF MSWINDOWS}  // case insensitive
 
-     Result := StrSame(Path1, Path2);
 
-     {$ELSE ~MSWINDOWS}  // case sensitive
 
-     Result := Path1 = Path2;
 
-     {$ENDIF ~MSWINDOWS}
 
-   end;
 
- begin
 
-   Origin := PathCanonicalize(Origin);
 
-   Destination := PathCanonicalize(Destination);
 
-   {$IFDEF MSWINDOWS}
 
-   OrigDrive := ExtractFileDrive(Origin);
 
-   DestDrive := ExtractFileDrive(Destination);
 
-   {$ENDIF MSWINDOWS}
 
-   if Equal(Origin, Destination) or (Destination = '') then
 
-     Result := '.'
 
-   else
 
-   if Origin = '' then
 
-     Result := Destination
 
-   else
 
-   {$IFDEF MSWINDOWS}
 
-   if (DestDrive <> '') and ((OrigDrive = '') or ((OrigDrive <> '') and not Equal(OrigDrive, DestDrive))) then
 
-     Result := Destination
 
-   else
 
-   if (OrigDrive <> '') and (Pos(DirDelimiter, Destination) = 1)
 
-     and not Equal(PathUncPrefix,Copy(Destination,1,Length(PathUncPrefix))) then
 
-     Result := OrigDrive + Destination  // prepend drive part from Origin
 
-   else
 
-   {$ENDIF MSWINDOWS}
 
-   if StartsFromRoot(Origin) and not StartsFromRoot(Destination) then
 
-     Result := StrEnsureSuffix(DirDelimiter, Origin) +
 
-       StrEnsureNoPrefix(DirDelimiter, Destination)
 
-   else
 
-   begin
 
-     // create a list of paths as separate strings
 
-     OrigList := TStringList.Create;
 
-     DestList := TStringList.Create;
 
-     try
 
-       // NOTE: DO NOT USE DELIMITER AND DELIMITEDTEXT FROM
 
-       // TSTRINGS, THEY WILL SPLIT PATHS WITH SPACES !!!!
 
-       StrToStrings(Origin, DirDelimiter, OrigList, False);
 
-       StrToStrings(Destination, DirDelimiter, DestList, False);
 
-       begin
 
-         // find the first directory that is not the same
 
-         DiffIndex := OrigList.Count;
 
-         if DestList.Count < DiffIndex then
 
-           DiffIndex := DestList.Count;
 
-         for I := 0 to DiffIndex - 1 do
 
-           if not Equal(OrigList[I], DestList[I]) then
 
-           begin
 
-             DiffIndex := I;
 
-             Break;
 
-           end;
 
-         Result := StrRepeat('..' + DirDelimiter, OrigList.Count - DiffIndex);
 
-         Result := PathRemoveSeparator(Result);
 
-         for I := DiffIndex to DestList.Count - 1 do
 
-         begin
 
-           if Result <> '' then
 
-             Result := Result + DirDelimiter;
 
-           Result := Result + DestList[i];
 
-         end;
 
-       end;
 
-     finally
 
-       DestList.Free;
 
-       OrigList.Free;
 
-     end;
 
-   end;
 
- end;
 
- function PathGetTempPath: string;
 
- {$IFDEF MSWINDOWS}
 
- var
 
-   BufSize: Cardinal;
 
- begin
 
-   BufSize := {$IFDEF HAS_UNITSCOPE}Winapi.{$ENDIF}Windows.GetTempPath(0, nil);
 
-   SetLength(Result, BufSize);
 
-   { TODO : Check length (-1 or not) }
 
-   {$IFDEF HAS_UNITSCOPE}Winapi.{$ENDIF}Windows.GetTempPath(BufSize, PChar(Result));
 
-   StrResetLength(Result);
 
- end;
 
- {$ENDIF MSWINDOWS}
 
- {$IFDEF UNIX}
 
- begin
 
-   Result := GetEnvironmentVariable('TMPDIR');
 
- end;
 
- {$ENDIF UNIX}
 
- function PathIsAbsolute(const Path: string): Boolean;
 
- {$IFDEF MSWINDOWS}
 
- var
 
-   I: Integer;
 
- {$ENDIF MSWINDOWS}
 
- begin
 
-   Result := False;
 
-   if Path <> '' then
 
-   begin
 
-     {$IFDEF UNIX}
 
-     Result := (Path[1] = DirDelimiter);
 
-     {$ENDIF UNIX}
 
-     {$IFDEF MSWINDOWS}
 
-     if not PathIsUnc(Path) then
 
-     begin
 
-       I := 0;
 
-       if PathIsDiskDevice(Path) then
 
-         I := Length(PathDevicePrefix);
 
-       Result := (Length(Path) > I + 2) and CharIsDriveLetter(Path[I + 1]) and
 
-         (Path[I + 2] = ':') and (Path[I + 3] = DirDelimiter);
 
-     end
 
-     else
 
-       Result := True;
 
-     {$ENDIF MSWINDOWS}
 
-   end;
 
- end;
 
- function PathIsChild(const Path, Base: string): Boolean;
 
- var
 
-   L: Integer;
 
-   B, P: string;
 
- begin
 
-   Result := False;
 
-   B := PathRemoveSeparator(Base);
 
-   P := PathRemoveSeparator(Path);
 
-   // an empty path or one that's not longer than base cannot be a subdirectory
 
-   L := Length(B);
 
-   if (P = '') or (L >= Length(P)) then
 
-     Exit;
 
-   {$IFDEF MSWINDOWS}
 
-   Result := AnsiSameText(StrLeft(P, L), B) and (P[L+1] = DirDelimiter);
 
-   {$ENDIF MSWINDOWS}
 
-   {$IFDEF UNIX}
 
-   Result := AnsiSameStr(StrLeft(P, L), B) and (P[L+1] = DirDelimiter);
 
-   {$ENDIF UNIX}
 
- end;
 
- function PathIsEqualOrChild(const Path, Base: string): Boolean;
 
- var
 
-   L: Integer;
 
-   B, P: string;
 
- begin
 
-   B := PathRemoveSeparator(Base);
 
-   P := PathRemoveSeparator(Path);
 
-   // an empty path or one that's not longer than base cannot be a subdirectory
 
-   L := Length(B);
 
-   {$IFDEF MSWINDOWS}
 
-   Result := AnsiSameText(P, B);
 
-   {$ENDIF MSWINDOWS}
 
-   {$IFDEF UNIX}
 
-   Result := AnsiSameStr(P, B);
 
-   {$ENDIF UNIX}
 
-   if Result or (P = '') or (L >= Length(P)) then
 
-     Exit;
 
-   {$IFDEF MSWINDOWS}
 
-   Result := AnsiSameText(StrLeft(P, L), B) and (P[L+1] = DirDelimiter);
 
-   {$ENDIF MSWINDOWS}
 
-   {$IFDEF UNIX}
 
-   Result := AnsiSameStr(StrLeft(P, L), B) and (P[L+1] = DirDelimiter);
 
-   {$ENDIF UNIX}
 
- end;
 
- function PathIsDiskDevice(const Path: string): Boolean;
 
- {$IFDEF UNIX}
 
- var
 
-   FullPath: string;
 
-   F: PIOFile;
 
-   Buffer: array [0..255] of AnsiChar;
 
-   MountEntry: TMountEntry;
 
-   FsTypes: TStringList;
 
-   procedure GetAvailableFileSystems(const List: TStrings);
 
-   var
 
-     F: TextFile;
 
-     S: string;
 
-   begin
 
-     AssignFile(F, '/proc/filesystems');
 
-     Reset(F);
 
-     repeat
 
-       Readln(F, S);
 
-       if Pos('nodev', S) = 0 then // how portable is this ?
 
-         List.Add(Trim(S));
 
-     until Eof(F);
 
-     List.Add('supermount');
 
-     CloseFile(F);
 
-   end;
 
- begin
 
-   Result := False;
 
-   SetLength(FullPath, _POSIX_PATH_MAX);
 
-   if realpath(PChar(Path), PChar(FullPath)) = nil then
 
-     RaiseLastOSError;
 
-   StrResetLength(FullPath);
 
-   FsTypes := TStringList.Create;
 
-   try
 
-     GetAvailableFileSystems(FsTypes);
 
-     F := setmntent(_PATH_MOUNTED, 'r'); // PATH_MOUNTED is deprecated,
 
-                                         // but PATH_MNTTAB is defective in Libc.pas
 
-     try
 
-       // get drives from mtab
 
-       while not Result and (getmntent_r(F, MountEntry, Buffer, SizeOf(Buffer)) <> nil) do
 
-         if FsTypes.IndexOf(MountEntry.mnt_type) <> -1 then
 
-           Result := MountEntry.mnt_dir = FullPath;
 
-     finally
 
-       endmntent(F);
 
-     end;
 
-   finally
 
-     FsTypes.Free;
 
-   end;
 
- end;
 
- {$ENDIF UNIX}
 
- {$IFDEF MSWINDOWS}
 
- begin
 
-   Result := Copy(Path, 1, Length(PathDevicePrefix)) = PathDevicePrefix;
 
- end;
 
- {$ENDIF MSWINDOWS}
 
- function CharIsMachineName(const C: Char): Boolean; {$IFDEF SUPPORTS_INLINE} inline; {$ENDIF}
 
- begin
 
-   case C of
 
-     'a'..'z',
 
-     'A'..'Z',
 
-     '-', '_', '.':
 
-       Result := True;
 
-   else
 
-     Result := False;
 
-   end;
 
- end;
 
- function CharIsInvalidFileNameCharacter(const C: Char): Boolean;
 
- begin
 
-   case C of
 
-     '<', '>', '?', '/', '\', ',', '*', '+', '=', '[', ']', '|', ':', ';', '"', '''':
 
-       Result := True;
 
-   else
 
-     Result := False;
 
-   end;
 
- end;
 
- function CharIsInvalidPathCharacter(const C: Char): Boolean;
 
- begin
 
-   case C of
 
-     '<', '>', '?',
 
-   {$IFDEF UNIX}
 
-     '/',
 
-   {$ELSE}
 
-     '\',
 
-   {$ENDIF}
 
-     ',', '*', '+', '=', '[', ']', '|', ':', ';', '"', '''':
 
-       Result := True;
 
-   else
 
-     Result := False;
 
-   end;
 
- end;
 
- function PathIsUNC(const Path: string): Boolean;
 
- {$IFDEF MSWINDOWS}
 
- const
 
-   cUNCSuffix = '?\UNC';
 
- var
 
-   P: PChar;
 
-   function AbsorbSeparator: Boolean;
 
-   begin
 
-     Result := (P <> nil) and (P^ = DirDelimiter);
 
-     if Result then
 
-       Inc(P);
 
-   end;
 
-   function AbsorbMachineName: Boolean;
 
-   var
 
-     NonDigitFound: Boolean;
 
-   begin
 
-     // a valid machine name is a string composed of the set [a-z, A-Z, 0-9, -, _] but it may not
 
-     // consist entirely out of numbers
 
-     Result := True;
 
-     NonDigitFound := False;
 
-     while (P^ <> #0) and (P^ <> DirDelimiter) do
 
-     begin
 
-       if CharIsMachineName(P^) then
 
-       begin
 
-         NonDigitFound := True;
 
-         Inc(P);
 
-       end
 
-       else
 
-       if CharIsDigit(P^) then
 
-         Inc(P)
 
-       else
 
-       begin
 
-         Result := False;
 
-         Break;
 
-       end;
 
-     end;
 
-     Result := Result and NonDigitFound;
 
-   end;
 
-   function AbsorbShareName: Boolean;
 
-   begin
 
-     // a valid share name is a string composed of a set the set !InvalidCharacters note that a
 
-     // leading '$' is valid (indicates a hidden share)
 
-     Result := True;
 
-     while (P^ <> #0) and (P^ <> DirDelimiter) do
 
-     begin
 
-       if CharIsInvalidPathCharacter(P^) then
 
-       begin
 
-         Result := False;
 
-         Break;
 
-       end;
 
-       Inc(P);
 
-     end;
 
-   end;
 
- begin
 
-   Result := Copy(Path, 1, Length(PathUncPrefix)) = PathUncPrefix;
 
-   if Result then
 
-   begin
 
-     if Copy(Path, 1, Length(PathUncPrefix + cUNCSuffix)) = PathUncPrefix + cUNCSuffix then
 
-       P := @Path[Length(PathUncPrefix + cUNCSuffix)]
 
-     else
 
-     begin
 
-       P := @Path[Length(PathUncPrefix)];
 
-       Result := AbsorbSeparator and AbsorbMachineName;
 
-     end;
 
-     Result := Result and AbsorbSeparator;
 
-     if Result then
 
-     begin
 
-       Result := AbsorbShareName;
 
-       // remaining, if anything, is path and or filename (optional) check those?
 
-     end;
 
-   end;
 
- end;
 
- {$ENDIF MSWINDOWS}
 
- {$IFDEF UNIX}
 
- begin
 
-   Result := False;
 
- end;
 
- {$ENDIF UNIX}
 
- function PathRemoveSeparator(const Path: string): string;
 
- var
 
-   L: Integer;
 
- begin
 
-   L := Length(Path);
 
-   if (L <> 0) and (Path[L] = DirDelimiter) then
 
-     Result := Copy(Path, 1, L - 1)
 
-   else
 
-     Result := Path;
 
- end;
 
- function PathRemoveExtension(const Path: string): string;
 
- var
 
-   I: Integer;
 
- begin
 
-   I := LastDelimiter(':.' + DirDelimiter, Path);
 
-   if (I > 0) and (Path[I] = '.') then
 
-     Result := Copy(Path, 1, I - 1)
 
-   else
 
-     Result := Path;
 
- end;
 
- {$IFDEF MSWINDOWS}
 
- function SHGetDisplayName(ShellFolder: IShellFolder; PIDL: PItemIDList; ForParsing: Boolean): string;
 
- const
 
-   Flags: array[Boolean] of DWORD = (SHGDN_NORMAL, SHGDN_FORPARSING);
 
- var
 
-   StrRet: TStrRet;
 
-   P: PChar;
 
- begin
 
-   Result := '';
 
-   StrRet.utype := 0;
 
-   ShellFolder.GetDisplayNameOf(PIDL, Flags[ForParsing], StrRet);
 
-   case StrRet.uType of
 
-     STRRET_CSTR:
 
-       SetString(Result, StrRet.cStr, lstrlenA(StrRet.cStr));
 
-     STRRET_OFFSET:
 
-       begin
 
-         P := @PIDL.mkid.abID[StrRet.uOffset - SizeOf(PIDL.mkid.cb)];
 
-         SetString(Result, P, PIDL.mkid.cb - StrRet.uOffset);
 
-       end;
 
-     STRRET_WSTR:
 
-       Result := StrRet.pOleStr;
 
-   end;
 
-   Result := Copy(Result, 1, lstrlen(PChar(Result)));
 
- end;
 
- function CutFirstDirectory(var Path: string): string;
 
- var
 
-   ps: Integer;
 
- begin
 
-   ps := AnsiPos(DirDelimiter, Path);
 
-   if ps > 0 then
 
-   begin
 
-     Result := Copy(Path, 1, ps - 1);
 
-     Path := Copy(Path, ps + 1, Length(Path));
 
-   end
 
-   else
 
-   begin
 
-     Result := Path;
 
-     Path := '';
 
-   end;
 
- end;
 
- function PathGetPhysicalPath(const LocalizedPath: string): string;
 
- var
 
-   Malloc: IMalloc;
 
-   DesktopFolder: IShellFolder;
 
-   RootFolder: IShellFolder;
 
-   Eaten: Cardinal;
 
-   Attributes: Cardinal;
 
-   pidl: PItemIDList;
 
-   EnumIDL: IEnumIDList;
 
-   Drive: WideString;
 
-   Featched: Cardinal;
 
-   ParsePath: WideString;
 
-   Path, Name: string;
 
-   Found: Boolean;
 
- begin
 
-   if StrCompareRange('\\', LocalizedPath, 1, 2) = 0 then
 
-   begin
 
-     Result := LocalizedPath;
 
-     Exit;
 
-   end;
 
-   Drive := ExtractFileDrive(LocalizedPath);
 
-   if Drive = '' then
 
-   begin
 
-     Result := LocalizedPath;
 
-     Exit;
 
-   end;
 
-   Path := Copy(LocalizedPath, Length(Drive) + 2, Length(LocalizedPath));
 
-   ParsePath := Drive;
 
-   OLECheck( SHGetMalloc(Malloc) );
 
-   OleCheck( SHGetDesktopFolder(DesktopFolder) );
 
-   while Path <> '' do
 
-   begin
 
-     Name := CutFirstDirectory(Path);
 
-     Found := False;
 
-     pidl := nil;
 
-     Attributes := 0;
 
-     if Succeeded( DesktopFolder.ParseDisplayName(0, nil, PWideChar(ParsePath), Eaten, pidl, Attributes) ) then
 
-     begin
 
-       OleCheck( DesktopFolder.BindToObject(pidl, nil, IShellFolder, RootFolder) );
 
-       Malloc.Free(pidl);
 
-       OleCheck( RootFolder.EnumObjects(0, SHCONTF_FOLDERS or SHCONTF_NONFOLDERS or SHCONTF_INCLUDEHIDDEN, EnumIDL) );
 
-       Featched := 0;
 
-       while EnumIDL.Next(1, pidl, Featched) = NOERROR do
 
-       begin
 
-         if AnsiCompareText(Name, SHGetDisplayName(RootFolder, pidl, False)) = 0 then
 
-         begin
 
-           ParsePath := SHGetDisplayName(RootFolder, pidl, True);
 
-           Malloc.Free(pidl);
 
-           Found := True;
 
-           Break;
 
-         end;
 
-         Malloc.Free(pidl);
 
-       end;
 
-       EnumIDL := nil;
 
-       RootFolder := nil;
 
-     end;
 
-     if not Found then
 
-       ParsePath := ParsePath + DirDelimiter + Name;
 
-   end;
 
-   Result := ParsePath;
 
- end;
 
- function PathGetLocalizedPath(const PhysicalPath: string): string;
 
- var
 
-   Malloc: IMalloc;
 
-   DesktopFolder: IShellFolder;
 
-   RootFolder: IShellFolder;
 
-   Eaten: Cardinal;
 
-   Attributes: Cardinal;
 
-   pidl: PItemIDList;
 
-   EnumIDL: IEnumIDList;
 
-   Drive: WideString;
 
-   Featched: Cardinal;
 
-   ParsePath: WideString;
 
-   Path, Name, ParseName, DisplayName: string;
 
-   Found: Boolean;
 
- begin
 
-   if StrCompareRange('\\', PhysicalPath, 1, 2) = 0 then
 
-   begin
 
-     Result := PhysicalPath;
 
-     Exit;
 
-   end;
 
-   Drive := ExtractFileDrive(PhysicalPath);
 
-   if Drive = '' then
 
-   begin
 
-     Result := PhysicalPath;
 
-     Exit;
 
-   end;
 
-   Path := Copy(PhysicalPath, Length(Drive) + 2, Length(PhysicalPath));
 
-   ParsePath := Drive;
 
-   Result := Drive;
 
-   OLECheck( SHGetMalloc(Malloc) );
 
-   OleCheck( SHGetDesktopFolder(DesktopFolder) );
 
-   while Path <> '' do
 
-   begin
 
-     Name := CutFirstDirectory(Path);
 
-     Found := False;
 
-     pidl := nil;
 
-     Attributes := 0;
 
-     if Succeeded( DesktopFolder.ParseDisplayName(0, nil, PWideChar(ParsePath), Eaten, pidl, Attributes) ) then
 
-     begin
 
-       OleCheck( DesktopFolder.BindToObject(pidl, nil, IShellFolder, RootFolder) );
 
-       Malloc.Free(pidl);
 
-       OleCheck( RootFolder.EnumObjects(0, SHCONTF_FOLDERS or SHCONTF_NONFOLDERS or SHCONTF_INCLUDEHIDDEN, EnumIDL) );
 
-       Featched := 0;
 
-       while EnumIDL.Next(1, pidl, Featched) = NOERROR do
 
-       begin
 
-         ParseName := SHGetDisplayName(RootFolder, pidl, True);
 
-         DisplayName := SHGetDisplayName(RootFolder, pidl, False);
 
-         Malloc.Free(pidl);
 
-         if (AnsiCompareText(Name, ExtractFileName(ParseName)) = 0) or
 
-            (AnsiCompareText(Name, DisplayName) = 0) then
 
-         begin
 
-           Name := DisplayName;
 
-           ParsePath := ParseName;
 
-           Found := True;
 
-           Break;
 
-         end;
 
-       end;
 
-       EnumIDL := nil;
 
-       RootFolder := nil;
 
-     end;
 
-     Result := Result + DirDelimiter + Name;
 
-     if not Found then
 
-       ParsePath := ParsePath + DirDelimiter + Name;
 
-   end;
 
- end;
 
- {$ELSE ~MSWINDOWS}
 
- function PathGetPhysicalPath(const LocalizedPath: string): string;
 
- begin
 
-   Result := LocalizedPath;
 
- end;
 
- function PathGetLocalizedPath(const PhysicalPath: string): string;
 
- begin
 
-   Result := PhysicalPath;
 
- end;
 
- {$ENDIF ~MSWINDOWS}
 
- //=== Files and Directories ==================================================
 
- {* Extended version of JclFileUtils.BuildFileList:
 
-    function parameter Path can include multiple FileMasks as:
 
-    c:\aaa\*.pas; pro*.dpr; *.d??
 
-    FileMask Seperator = ';'
 
-  *}
 
- function BuildFileList(const Path: string; const Attr: Integer; const List: TStrings; IncludeDirectoryName: Boolean =
 
-     False): Boolean;
 
- var
 
-   SearchRec: TSearchRec;
 
-   IndexMask: Integer;
 
-   MaskList: TStringList;
 
-   Masks, Directory: string;
 
- begin
 
-   Assert(List <> nil);
 
-   MaskList := TStringList.Create;
 
-   try
 
-     {* extract the Directory *}
 
-     Directory := ExtractFileDir(Path);
 
-     {* files can be searched in the current directory *}
 
-     if Directory <> '' then
 
-     begin
 
-       Directory := PathAddSeparator(Directory);
 
-       {* extract the FileMasks portion out of Path *}
 
-       Masks := StrAfter(Directory, Path);
 
-     end
 
-     else
 
-       Masks := Path;
 
-     {* put the Masks into TStringlist *}
 
-     StrTokenToStrings(Masks, DirSeparator, MaskList);
 
-     {* search all files in the directory *}
 
-     Result := FindFirst(Directory + '*', faAnyFile, SearchRec) = 0;
 
-     List.BeginUpdate;
 
-     try
 
-       while Result do
 
-       begin
 
-         {* if the filename matches any mask then it is added to the list *}
 
-         for IndexMask := 0 to MaskList.Count - 1 do
 
-           if (SearchRec.Name <> '.') and (SearchRec.Name <> '..')
 
-             and ((SearchRec.Attr and Attr) = (SearchRec.Attr and faAnyFile))
 
-             and IsFileNameMatch(SearchRec.Name, MaskList.Strings[IndexMask]) then
 
-         begin
 
-           if IncludeDirectoryName then
 
-             List.Add(Directory+SearchRec.Name)
 
-           else
 
-             List.Add(SearchRec.Name);
 
-           Break;
 
-         end;
 
-         case FindNext(SearchRec) of
 
-           0:
 
-             ;
 
-           ERROR_NO_MORE_FILES:
 
-             Break;
 
-           else
 
-             Result := False;
 
-         end;
 
-       end;
 
-     finally
 
-       {$IFDEF HAS_UNITSCOPE}System.{$ENDIF}SysUtils.FindClose(SearchRec);
 
-       List.EndUpdate;
 
-     end;
 
-   finally
 
-     MaskList.Free;
 
-   end;
 
- end;
 
- {$IFDEF MSWINDOWS}
 
- procedure CreateEmptyFile(const FileName: string);
 
- var
 
-   Handle: THandle;
 
- begin
 
-   Handle := CreateFile(PChar(FileName), GENERIC_READ or GENERIC_WRITE, 0, nil, CREATE_ALWAYS, 0, 0);
 
-   if Handle <> INVALID_HANDLE_VALUE then
 
-     CloseHandle(Handle)
 
-   else
 
-     RaiseLastOSError;
 
- end;
 
- {$ENDIF MSWINDOWS}
 
- {$IFDEF MSWINDOWS}
 
- function CloseVolume(var Volume: THandle): Boolean;
 
- begin
 
-   Result := False;
 
-   if Volume <> INVALID_HANDLE_VALUE then
 
-   begin
 
-     Result := CloseHandle(Volume);
 
-     if Result then
 
-       Volume := INVALID_HANDLE_VALUE;
 
-   end;
 
- end;
 
- {$IFNDEF FPC}  // needs JclShell
 
- {$IFNDEF WINSCP}
 
- function DeleteDirectory(const DirectoryName: string; MoveToRecycleBin: Boolean): Boolean;
 
- begin
 
-   if MoveToRecycleBin then
 
-     Result := SHDeleteFolder(0, DirectoryName, [doSilent, doAllowUndo])
 
-   else
 
-     Result := DelTree(DirectoryName);
 
- end;
 
- {$ENDIF ~WINSCP}
 
- function CopyDirectory(ExistingDirectoryName, NewDirectoryName: string): Boolean;
 
- var
 
-   SH: SHFILEOPSTRUCT;
 
- begin
 
-   ResetMemory(SH, SizeOf(SH));
 
-   SH.Wnd    := 0;
 
-   SH.wFunc  := FO_COPY;
 
-   SH.pFrom  := PChar(PathRemoveSeparator(ExistingDirectoryName) + #0);
 
-   SH.pTo    := PChar(PathRemoveSeparator(NewDirectoryName) + #0);
 
-   SH.fFlags := FOF_ALLOWUNDO or FOF_NOCONFIRMATION or FOF_NOCONFIRMMKDIR or FOF_SILENT;
 
-   Result := SHFileOperation(SH) = 0;
 
- end;
 
- function MoveDirectory(ExistingDirectoryName, NewDirectoryName: string): Boolean;
 
- var
 
-   SH: SHFILEOPSTRUCT;
 
- begin
 
-   ResetMemory(SH, SizeOf(SH));
 
-   SH.Wnd    := 0;
 
-   SH.wFunc  := FO_MOVE;
 
-   SH.pFrom  := PChar(PathRemoveSeparator(ExistingDirectoryName) + #0);
 
-   SH.pTo    := PChar(PathRemoveSeparator(NewDirectoryName) + #0);
 
-   SH.fFlags := FOF_ALLOWUNDO or FOF_NOCONFIRMATION or FOF_NOCONFIRMMKDIR or FOF_SILENT;
 
-   Result := SHFileOperation(SH) = 0;
 
- end;
 
- {$ENDIF ~FPC}
 
- function DelTree(const Path: string): Boolean;
 
- begin
 
-   Result := DelTreeEx(Path, False, nil);
 
- end;
 
- function DelTreeEx(const Path: string; AbortOnFailure: Boolean; Progress: TDelTreeProgress): Boolean;
 
- var
 
-   Files: TStringList;
 
-   LPath: string; // writable copy of Path
 
-   FileName: string;
 
-   I: Integer;
 
-   PartialResult: Boolean;
 
-   Attr: DWORD;
 
- begin
 
-   Assert(Path <> '', LoadResString(@RsDelTreePathIsEmpty));
 
-   {$IFNDEF ASSERTIONS_ON}
 
-   if Path = '' then
 
-   begin
 
-     Result := False;
 
-     Exit;
 
-   end;
 
-   {$ENDIF ~ASSERTIONS_ON}
 
-   Result := True;
 
-   Files := TStringList.Create;
 
-   try
 
-     LPath := PathRemoveSeparator(Path);
 
-     BuildFileList(LPath + '\*.*', faAnyFile, Files);
 
-     for I := 0 to Files.Count - 1 do
 
-     begin
 
-       FileName := LPath + DirDelimiter + Files[I];
 
-       PartialResult := True;
 
-       // If the current file is itself a directory then recursively delete it
 
-       Attr := GetFileAttributes(PChar(FileName));
 
-       if (Attr <> DWORD(-1)) and ((Attr and FILE_ATTRIBUTE_DIRECTORY) <> 0) then
 
-         PartialResult := DelTreeEx(FileName, AbortOnFailure, Progress)
 
-       else
 
-       begin
 
-         if Assigned(Progress) then
 
-           PartialResult := Progress(FileName, Attr);
 
-         if PartialResult then
 
-         begin
 
-           // Set attributes to normal in case it's a readonly file
 
-           PartialResult := SetFileAttributes(PChar(FileName), FILE_ATTRIBUTE_NORMAL);
 
-           if PartialResult then
 
-             PartialResult := DeleteFile(FileName);
 
-         end;
 
-       end;
 
-       if not PartialResult then
 
-       begin
 
-         Result := False;
 
-         if AbortOnFailure then
 
-           Break;
 
-       end;
 
-     end;
 
-   finally
 
-     FreeAndNil(Files);
 
-   end;
 
-   if Result then
 
-   begin
 
-     // Finally remove the directory itself
 
-     Result := SetFileAttributes(PChar(LPath), FILE_ATTRIBUTE_NORMAL);
 
-     if Result then
 
-     begin
 
-       {$IOCHECKS OFF}
 
-       RmDir(LPath);
 
-       {$IFDEF IOCHECKS_ON}
 
-       {$IOCHECKS ON}
 
-       {$ENDIF IOCHECKS_ON}
 
-       Result := IOResult = 0;
 
-     end;
 
-   end;
 
- end;
 
- {$ENDIF MSWINDOWS}
 
- {$IFDEF MSWINDOWS}
 
- function DirectoryExists(const Name: string): Boolean;
 
- var
 
-   R: DWORD;
 
- begin
 
-   R := GetFileAttributes(PChar(Name));
 
-   Result := (R <> DWORD(-1)) and ((R and FILE_ATTRIBUTE_DIRECTORY) <> 0);
 
- end;
 
- {$ENDIF MSWINDOWS}
 
- {$IFDEF UNIX}
 
- function DirectoryExists(const Name: string; ResolveSymLinks: Boolean): Boolean;
 
- begin
 
-   Result := IsDirectory(Name, ResolveSymLinks);
 
- end;
 
- {$ENDIF UNIX}
 
- {$IFDEF MSWINDOWS}
 
- function DiskInDrive(Drive: Char): Boolean;
 
- var
 
-   ErrorMode: Cardinal;
 
- begin
 
-   Result := False;
 
-   Assert(CharIsDriveLetter(Drive));
 
-   if CharIsDriveLetter(Drive) then
 
-   begin
 
-     Drive := CharUpper(Drive);
 
-     { try to access the drive, it doesn't really matter how we access the drive and as such calling
 
-       DiskSize is more or less a random choice. The call to SetErrorMode supresses the system provided
 
-       error dialog if there is no disk in the drive and causes the to DiskSize to fail. }
 
-     ErrorMode := SetErrorMode(SEM_FAILCRITICALERRORS);
 
-     try
 
-       Result := DiskSize(Ord(Drive) - $40) <> -1;
 
-     finally
 
-       SetErrorMode(ErrorMode);
 
-     end;
 
-   end;
 
- end;
 
- {$ENDIF MSWINDOWS}
 
- function FileCreateTemp(var Prefix: string): THandle;
 
- {$IFDEF MSWINDOWS}
 
- var
 
-   TempName: string;
 
- begin
 
-   Result := INVALID_HANDLE_VALUE;
 
-   TempName := FileGetTempName(Prefix);
 
-   if TempName <> '' then
 
-   begin
 
-     Result := CreateFile(PChar(TempName), GENERIC_READ or GENERIC_WRITE, 0, nil,
 
-       OPEN_EXISTING, FILE_ATTRIBUTE_TEMPORARY or FILE_FLAG_DELETE_ON_CLOSE, 0);
 
-     // In certain situations it's possible that CreateFile fails yet the file is actually created,
 
-     // therefore explicitly delete it upon failure.
 
-     if Result = INVALID_HANDLE_VALUE then
 
-       DeleteFile(TempName);
 
-     Prefix := TempName;
 
-   end;
 
- end;
 
- {$ENDIF MSWINDOWS}
 
- {$IFDEF UNIX}
 
- var
 
-   Template: string;
 
- begin
 
-   // The mkstemp function generates a unique file name just as mktemp does, but
 
-   // it also opens the file for you with open. If successful, it modifies
 
-   // template in place and returns a file descriptor for that file open for
 
-   // reading and writing. If mkstemp cannot create a uniquely-named file, it
 
-   // returns -1. If template does not end with `XXXXXX', mkstemp returns -1 and
 
-   // does not modify template.
 
-   // The file is opened using mode 0600. If the file is meant to be used by
 
-   // other users this mode must be changed explicitly.
 
-   // Unlike mktemp, mkstemp is actually guaranteed to create a unique file that
 
-   // cannot possibly clash with any other program trying to create a temporary
 
-   // file. This is because it works by calling open with the O_EXCL flag, which
 
-   // says you want to create a new file and get an error if the file already
 
-   // exists.
 
-   Template := Prefix + 'XXXXXX';
 
-   Result := mkstemp(PChar(Template));
 
-   Prefix := Template;
 
- end;
 
- {$ENDIF UNIX}
 
- {$IFNDEF WINSCP}
 
- function FileBackup(const FileName: string; Move: Boolean = False): Boolean;
 
- begin
 
-   if Move then
 
-     Result := FileMove(FileName, GetBackupFileName(FileName), True)
 
-   else
 
-     Result := FileCopy(FileName, GetBackupFileName(FileName), True);
 
- end;
 
- {$ENDIF ~WINSCP}
 
- function FileCopy(const ExistingFileName, NewFileName: string; ReplaceExisting: Boolean = False): Boolean;
 
- var
 
-   {$IFDEF UNIX}
 
-   SrcFile, DstFile: file;
 
-   Buf: array[0..511] of Byte;
 
-   BytesRead: Integer;
 
-   {$ENDIF UNIX}
 
-   DestFileName: string;
 
- begin
 
-   if IsDirectory(NewFileName) then
 
-     DestFileName := PathAddSeparator(NewFileName) + ExtractFileName(ExistingFileName)
 
-   else
 
-     DestFileName := NewFileName;
 
-   {$IFDEF MSWINDOWS}
 
-   { TODO : Use CopyFileEx where available? }
 
-   Result := CopyFile(PChar(ExistingFileName), PChar(DestFileName), not ReplaceExisting);
 
-   {$ENDIF MSWINDOWS}
 
-   {$IFDEF UNIX}
 
-   Result := False;
 
-   if not FileExists(DestFileName) or ReplaceExisting then
 
-   begin
 
-     AssignFile(SrcFile, ExistingFileName);
 
-     Reset(SrcFile, 1);
 
-     AssignFile(DstFile, DestFileName);
 
-     Rewrite(DstFile, 1);
 
-     while not Eof(SrcFile) do
 
-     begin
 
-       BlockRead(SrcFile, Buf, SizeOf(Buf), BytesRead);
 
-       BlockWrite(DstFile, Buf, BytesRead);
 
-     end;
 
-     CloseFile(DstFile);
 
-     CloseFile(SrcFile);
 
-     Result := True;
 
-   end;
 
-   {$ENDIF UNIX}
 
- end;
 
- function FileDateTime(const FileName: string): TDateTime;
 
- {$IFNDEF COMPILER10_UP}
 
- var
 
-   Age: Longint;
 
- {$ENDIF !COMPILER10_UP}
 
- begin
 
-   {$IFDEF COMPILER10_UP}
 
-   if not FileAge(Filename, Result) then
 
-     Result := 0;
 
-   {$ELSE}
 
-   Age := FileAge(FileName);
 
-   {$IFDEF MSWINDOWS}
 
-   // [roko] -1 is valid FileAge value on Linux
 
-   if Age = -1 then
 
-     Result := 0
 
-   else
 
-   {$ENDIF MSWINDOWS}
 
-     Result := FileDateToDateTime(Age);
 
-   {$ENDIF COMPILER10_UP}
 
- end;
 
- {$IFNDEF WINSCP}
 
- function FileDelete(const FileName: string; MoveToRecycleBin: Boolean = False): Boolean;
 
- {$IFDEF MSWINDOWS}
 
- begin
 
-   if MoveToRecycleBin then
 
-     Result := SHDeleteFiles(0, FileName, [doSilent, doAllowUndo, doFilesOnly])
 
-   else
 
-     Result := {$IFDEF HAS_UNITSCOPE}Winapi.{$ENDIF}Windows.DeleteFile(PChar(FileName));
 
- end;
 
- {$ENDIF MSWINDOWS}
 
- {$IFDEF UNIX}
 
-   { TODO : implement MoveToRecycleBin for appropriate Desktops (e.g. KDE) }
 
- begin
 
-   Result := remove(PChar(FileName)) <> -1;
 
- end;
 
- {$ENDIF UNIX}
 
- {$ENDIF ~WINSCP}
 
- function FileExists(const FileName: string): Boolean;
 
- {$IFDEF MSWINDOWS}
 
- var
 
-   Attr: Cardinal;
 
- {$ENDIF MSWINDOWS}
 
- begin
 
-   if FileName <> '' then
 
-   begin
 
-     {$IFDEF MSWINDOWS}
 
-     // FileGetSize is very slow, GetFileAttributes is much faster
 
-     Attr := GetFileAttributes(Pointer(Filename));
 
-     Result := (Attr <> $FFFFFFFF) and (Attr and FILE_ATTRIBUTE_DIRECTORY = 0);
 
-     {$ELSE ~MSWINDOWS}
 
-     // Attempt to access the file, doesn't matter how, using FileGetSize is as good as anything else.
 
-     Result := FileGetSize(FileName) <> -1;
 
-     {$ENDIF ~MSWINDOWS}
 
-   end
 
-   else
 
-     Result := False;
 
- end;
 
- {$IFNDEF WINSCP}
 
- procedure FileHistory(const FileName: string; HistoryPath: string = ''; MaxHistoryCount: Integer = 100; MinFileDate:
 
-     TDateTime = 0; ReplaceExtention: Boolean = true);
 
-   Function Extention (Number : Integer) : String;
 
-   begin
 
-     Result := inttostr(Number);
 
-     while Length(Result) < 3 do
 
-       Result := '0' + Result;
 
-     Result := '.~'+Result+'~';
 
-   end;
 
-   procedure RenameToNumber(const RenameFileName: string; Number: Integer);
 
-   var
 
-     f1: string;
 
-     f2: string;
 
-   begin
 
-     f1 := ChangeFileExt(RenameFileName,Extention(Number-1));
 
-     f2 := ChangeFileExt(RenameFileName,Extention(Number));
 
-     if FileExists(f2) then
 
-       if Number >= MaxHistoryCount then
 
-         if not FileDelete(f2) then
 
-           Exception.Create('Unable to delete file "' + f2 + '".')
 
-         else
 
-       else
 
-         RenameToNumber(RenameFileName, Number + 1);
 
-     if FileExists(f1) then
 
-       if not FileMove(f1, f2, true) then
 
-         Exception.Create('Unable to rename file "' + f1 + '" to "' + f2 + '".')
 
-   end;
 
- Var FirstFile : string;
 
- begin
 
-   // TODO -cMM: FileHistory default body inserted
 
-   if not FileExists(FileName) or (MaxHistoryCount <= 0) then
 
-     Exit;
 
-   if HistoryPath = '' then
 
-     HistoryPath := ExtractFilePath(FileName);
 
-   FirstFile := PathAppend(HistoryPath, ExtractFileName(FileName));
 
-   if ReplaceExtention then
 
-     FirstFile := ChangeFileExt(FirstFile, Extention(1))
 
-   else
 
-     FirstFile := FirstFile+Extention(1);
 
-   if (FileDateTime(FirstFile) > MinFileDate) and (MinFileDate <> 0) then
 
-     Exit;
 
-   RenameToNumber(FirstFile, 2);
 
-   FileCopy(FileName, FirstFile, True);
 
- end;
 
- {$ENDIF ~WINSCP}
 
- {$IFNDEF WINSCP}
 
- function FileMove(const ExistingFileName, NewFileName: string; ReplaceExisting: Boolean = False): Boolean;
 
- {$IFDEF MSWINDOWS}
 
- const
 
-   Flag: array[Boolean] of Cardinal = (0, MOVEFILE_REPLACE_EXISTING);
 
- {$ENDIF MSWINDOWS}
 
- begin
 
-   {$IFDEF MSWINDOWS}
 
-   Result := MoveFileEx(PChar(ExistingFileName), PChar(NewFileName), Flag[ReplaceExisting]);
 
-   {$ENDIF MSWINDOWS}
 
-   {$IFDEF UNIX}
 
-   Result := __rename(PChar(ExistingFileName), PChar(NewFileName)) = 0;
 
-   {$ENDIF UNIX}
 
-   if not Result then
 
-   begin
 
-     Result := FileCopy(ExistingFileName, NewFileName, ReplaceExisting);
 
-     if Result then
 
-       FileDelete(ExistingFileName);
 
-   end;
 
- end;
 
- function FileRestore(const FileName: string): Boolean;
 
- var
 
-   TempFileName: string;
 
- begin
 
-   Result := False;
 
-   TempFileName := FileGetTempName('');
 
-   if FileMove(GetBackupFileName(FileName), TempFileName, True) then
 
-     if FileBackup(FileName, False) then
 
-       Result := FileMove(TempFileName, FileName, True);
 
- end;
 
- {$ENDIF ~WINSCP}
 
- function GetBackupFileName(const FileName: string): string;
 
- var
 
-   NewExt: string;
 
- begin
 
-   NewExt := ExtractFileExt(FileName);
 
-   if Length(NewExt) > 0 then
 
-   begin
 
-     NewExt[1] := '~';
 
-     NewExt := '.' + NewExt
 
-   end
 
-   else
 
-     NewExt := '.~';
 
-   Result := ChangeFileExt(FileName, NewExt);
 
- end;
 
- function IsBackupFileName(const FileName: string): Boolean;
 
- begin
 
-   Result := (pos('.~', ExtractFileExt(FileName)) = 1);
 
- end;
 
- function FileGetDisplayName(const FileName: string): string;
 
- {$IFDEF MSWINDOWS}
 
- var
 
-   FileInfo: TSHFileInfo;
 
- begin
 
-   ResetMemory(FileInfo, SizeOf(FileInfo));
 
-   if SHGetFileInfo(PChar(FileName), 0, FileInfo, SizeOf(FileInfo), SHGFI_DISPLAYNAME) <> 0 then
 
-     Result := FileInfo.szDisplayName
 
-   else
 
-     Result := FileName;
 
- end;
 
- {$ELSE ~MSWINDOWS}
 
- begin
 
-   { TODO -cHelp : mention this reduced solution }
 
-   Result := FileName;
 
- end;
 
- {$ENDIF ~MSWINDOWS}
 
- {$IFNDEF WINSCP}
 
- function FileGetGroupName(const FileName: string {$IFDEF UNIX}; ResolveSymLinks: Boolean = True {$ENDIF}): string;
 
- {$IFDEF MSWINDOWS}
 
- var
 
-   DomainName: WideString;
 
-   TmpResult: WideString;
 
-   pSD: PSecurityDescriptor;
 
-   BufSize: DWORD;
 
- begin
 
-   if IsWinNT then
 
-   begin
 
-     BufSize := 0;
 
-     GetFileSecurity(PChar(FileName), GROUP_SECURITY_INFORMATION, nil, 0, BufSize);
 
-     if BufSize > 0 then
 
-     begin
 
-       GetMem(pSD, BufSize);
 
-       GetFileSecurity(PChar(FileName), GROUP_SECURITY_INFORMATION,
 
-         pSD, BufSize, BufSize);
 
-       LookupAccountBySid(Pointer(TJclAddr(pSD) + TJclAddr(pSD^.Group)), TmpResult, DomainName, True);
 
-       FreeMem(pSD);
 
-       Result := Trim(TmpResult);
 
-     end;
 
-   end;
 
- end;
 
- {$ENDIF ~MSWINDOWS}
 
- {$IFDEF UNIX}
 
- var
 
-   Buf: TStatBuf64;
 
-   ResultBuf: TGroup;
 
-   ResultBufPtr: PGroup;
 
-   Buffer: array of Char;
 
- begin
 
-   if GetFileStatus(FileName, Buf, ResolveSymLinks) = 0 then
 
-   begin
 
-     SetLength(Buffer, 128);
 
-     while getgrgid_r(Buf.st_gid, ResultBuf, @Buffer[0], Length(Buffer), ResultBufPtr) = ERANGE do
 
-       SetLength(Buffer, Length(Buffer) * 2);
 
-     Result := ResultBuf.gr_name;
 
-   end;
 
- end;
 
- {$ENDIF ~UNIX}
 
- function FileGetOwnerName(const FileName: string {$IFDEF UNIX}; ResolveSymLinks: Boolean = True {$ENDIF}): string;
 
- {$IFDEF MSWINDOWS}
 
- var
 
-   DomainName: WideString;
 
-   TmpResult: WideString;
 
-   pSD: PSecurityDescriptor;
 
-   BufSize: DWORD;
 
- begin
 
-   if IsWinNT then
 
-   begin
 
-     BufSize := 0;
 
-     GetFileSecurity(PChar(FileName), OWNER_SECURITY_INFORMATION, nil, 0, BufSize);
 
-     if BufSize > 0 then
 
-     begin
 
-       GetMem(pSD, BufSize);
 
-       try
 
-         GetFileSecurity(PChar(FileName), OWNER_SECURITY_INFORMATION,
 
-           pSD, BufSize, BufSize);
 
-         LookupAccountBySid(Pointer(TJclAddr(pSD) + TJclAddr(pSD^.Owner)), TmpResult, DomainName, True);
 
-       finally
 
-         FreeMem(pSD);
 
-       end;
 
-       Result := Trim(TmpResult);
 
-     end;
 
-   end;
 
- end;
 
- {$ENDIF ~MSWINDOWS}
 
- {$IFDEF UNIX}
 
- var
 
-   Buf: TStatBuf64;
 
-   ResultBuf: TPasswordRecord;
 
-   ResultBufPtr: PPasswordRecord;
 
-   Buffer: array of Char;
 
- begin
 
-   if GetFileStatus(FileName, Buf, ResolveSymLinks) = 0 then
 
-   begin
 
-     SetLength(Buffer, 128);
 
-     while getpwuid_r(Buf.st_uid, ResultBuf, @Buffer[0], Length(Buffer), ResultBufPtr) = ERANGE do
 
-       SetLength(Buffer, Length(Buffer) * 2);
 
-     Result := ResultBuf.pw_name;
 
-   end;
 
- end;
 
- {$ENDIF ~UNIX}
 
- {$ENDIF ~WINSCP}
 
- function FileGetSize(const FileName: string): Int64;
 
- {$IFDEF MSWINDOWS}
 
- var
 
-   FileAttributesEx: WIN32_FILE_ATTRIBUTE_DATA;
 
-   OldMode: Cardinal;
 
-   Size: TJclULargeInteger;
 
- begin
 
-   Result := -1;
 
-   OldMode := SetErrorMode(SEM_FAILCRITICALERRORS);
 
-   try
 
-     if GetFileAttributesEx(PChar(FileName), GetFileExInfoStandard, @FileAttributesEx) then
 
-     begin
 
-       Size.LowPart := FileAttributesEx.nFileSizeLow;
 
-       Size.HighPart := FileAttributesEx.nFileSizeHigh;
 
-       Result := Size.QuadPart;
 
-     end;
 
-   finally
 
-     SetErrorMode(OldMode);
 
-   end;
 
- end;
 
- {$ENDIF MSWINDOWS}
 
- {$IFDEF UNIX}
 
- var
 
-   Buf: TStatBuf64;
 
- begin
 
-   Result := -1;
 
-   if GetFileStatus(FileName, Buf, False) = 0 then
 
-     Result := Buf.st_size;
 
- end;
 
- {$ENDIF UNIX}
 
- {$IFDEF MSWINDOWS}
 
- {$IFDEF FPC}
 
- { TODO : Move this over to JclWin32 when JclWin32 gets overhauled. }
 
- function GetTempFileName(lpPathName, lpPrefixString: PChar;
 
-   uUnique: UINT; lpTempFileName: PChar): UINT; stdcall;
 
- external kernel32 name 'GetTempFileNameA';
 
- {$ENDIF FPC}
 
- {$ENDIF MSWINDOWS}
 
- function FileGetTempName(const Prefix: string): string;
 
- {$IFDEF MSWINDOWS}
 
- var
 
-   TempPath, TempFile: string;
 
-   R: Cardinal;
 
- begin
 
-   Result := '';
 
-   TempPath := PathGetTempPath;
 
-   if TempPath <> '' then
 
-   begin
 
-     SetLength(TempFile, MAX_PATH);
 
-     R := GetTempFileName(PChar(TempPath), PChar(Prefix), 0, PChar(TempFile));
 
-     if R <> 0 then
 
-     begin
 
-       StrResetLength(TempFile);
 
-       Result := TempFile;
 
-     end;
 
-   end;
 
- end;
 
- {$ENDIF MSWINDOWS}
 
- {$IFDEF UNIX}
 
- // Warning: Between the time the pathname is constructed and the file is created
 
- // another process might have created a file with the same name using tmpnam,
 
- // leading to a possible security hole. The implementation generates names which
 
- // can hardly be predicted, but when opening the file you should use the O_EXCL
 
- // flag. Using tmpfile or mkstemp is a safe way to avoid this problem.
 
- var
 
-   P: PChar;
 
- begin
 
-   P := tempnam(PChar(PathGetTempPath), PChar(Prefix));
 
-   Result := P;
 
-   Libc.free(P);
 
- end;
 
- {$ENDIF UNIX}
 
- {$IFDEF MSWINDOWS}
 
- function FileGetTypeName(const FileName: string): string;
 
- var
 
-   FileInfo: TSHFileInfo;
 
-   RetVal: DWORD;
 
- begin
 
-   ResetMemory(FileInfo, SizeOf(FileInfo));
 
-   RetVal := SHGetFileInfo(PChar(FileName), 0, FileInfo, SizeOf(FileInfo),
 
-     SHGFI_TYPENAME or SHGFI_USEFILEATTRIBUTES);
 
-   if RetVal <> 0 then
 
-     Result := FileInfo.szTypeName;
 
-   if (RetVal = 0) or (Trim(Result) = '') then
 
-   begin
 
-     // Lookup failed so mimic explorer behaviour by returning "XYZ File"
 
-     Result := ExtractFileExt(FileName);
 
-     Delete(Result, 1, 1);
 
-     Result := TrimLeft(UpperCase(Result) + LoadResString(@RsDefaultFileTypeName));
 
-   end;
 
- end;
 
- {$ENDIF MSWINDOWS}
 
- function FindUnusedFileName(FileName: string; const FileExt: string; NumberPrefix: string = ''): string;
 
- var
 
-   I: Integer;
 
- begin
 
-   Result := PathAddExtension(FileName, FileExt);
 
-   if not FileExists(Result) then
 
-     Exit;
 
-   if SameText(Result, FileName) then
 
-     Delete(FileName, Length(FileName) - Length(FileExt) + 1, Length(FileExt));
 
-   I := 0;
 
-   repeat
 
-     Inc(I);
 
-     Result := PathAddExtension(FileName + NumberPrefix + IntToStr(I), FileExt);
 
-   until not FileExists(Result);
 
- end;
 
- // This routine is copied from FileCtrl.pas to avoid dependency on that unit.
 
- // See the remark at the top of this section
 
- function ForceDirectories(Name: string): Boolean;
 
- var
 
-   ExtractPath: string;
 
- begin
 
-   Result := True;
 
-   if Length(Name) = 0 then
 
-     raise EJclFileUtilsError.CreateRes(@RsCannotCreateDir);
 
-   Name := PathRemoveSeparator(Name);
 
-   {$IFDEF MSWINDOWS}
 
-   ExtractPath := ExtractFilePath(Name);
 
-   if ((Length(Name) = 2) and (Copy(Name, 2,1) = ':')) or DirectoryExists(Name) or (ExtractPath = Name) then
 
-     Exit;
 
-   {$ENDIF MSWINDOWS}
 
-   {$IFDEF UNIX}
 
-   if (Length(Name) = 0) or DirectoryExists(Name) then
 
-     Exit;
 
-   ExtractPath := ExtractFilePath(Name);
 
-   {$ENDIF UNIX}
 
-   Result := (ExtractPath = '') or ForceDirectories(ExtractPath);
 
-   if Result then
 
-   begin
 
-     {$IFDEF MSWINDOWS}
 
-     SetLastError(ERROR_SUCCESS);
 
-     {$ENDIF MSWINDOWS}
 
-     Result := Result and CreateDir(Name);
 
-     {$IFDEF MSWINDOWS}
 
-     Result := Result or (GetLastError = ERROR_ALREADY_EXISTS);
 
-     {$ENDIF MSWINDOWS}
 
-   end;
 
- end;
 
- function GetDirectorySize(const Path: string): Int64;
 
-   function RecurseFolder(const Path: string): Int64;
 
-   var
 
-     F: TSearchRec;
 
-     R: Integer;
 
-     {$IFDEF MSWINDOWS}
 
-     TempSize: TJclULargeInteger;
 
-     {$ENDIF MSWINDOWS}
 
-   begin
 
-     Result := 0;
 
-     R := {$IFDEF HAS_UNITSCOPE}System.{$ENDIF}SysUtils.FindFirst(Path + '*.*', faAnyFile, F);
 
-     if R = 0 then
 
-     try
 
-       while R = 0 do
 
-       begin
 
-         if (F.Name <> '.') and (F.Name <> '..') then
 
-         begin
 
-           if (F.Attr and faDirectory) = faDirectory then
 
-             Inc(Result, RecurseFolder(Path + F.Name + DirDelimiter))
 
-           else
 
-           {$IFDEF MSWINDOWS}
 
-           begin
 
-             TempSize.LowPart := F.FindData.nFileSizeLow;
 
-             TempSize.HighPart := F.FindData.nFileSizeHigh;
 
-             Inc(Result, TempSize.QuadPart);
 
-           end;
 
-           {$ENDIF MSWINDOWS}
 
-           {$IFDEF UNIX}
 
-             // SysUtils.Find* don't perceive files >= 2 GB anyway
 
-             Inc(Result, Int64(F.Size));
 
-           {$ENDIF UNIX}
 
-         end;
 
-         R := {$IFDEF HAS_UNITSCOPE}System.{$ENDIF}SysUtils.FindNext(F);
 
-       end;
 
-       if R <> ERROR_NO_MORE_FILES then
 
-         Abort;
 
-     finally
 
-       {$IFDEF HAS_UNITSCOPE}System.{$ENDIF}SysUtils.FindClose(F);
 
-     end;
 
-   end;
 
- begin
 
-   if not DirectoryExists(PathRemoveSeparator(Path)) then
 
-     Result := -1
 
-   else
 
-   try
 
-     Result := RecurseFolder(PathAddSeparator(Path))
 
-   except
 
-     Result := -1;
 
-   end;
 
- end;
 
- {$IFDEF MSWINDOWS}
 
- function GetDriveTypeStr(const Drive: Char): string;
 
- var
 
-   DriveType: Integer;
 
-   DriveStr: string;
 
- begin
 
-   if not CharIsDriveLetter(Drive) then
 
-     raise EJclPathError.CreateResFmt(@RsPathInvalidDrive, [Drive]);
 
-   DriveStr := Drive + ':\';
 
-   DriveType := GetDriveType(PChar(DriveStr));
 
-   case DriveType of
 
-     DRIVE_REMOVABLE:
 
-       Result := LoadResString(@RsRemovableDrive);
 
-     DRIVE_FIXED:
 
-       Result := LoadResString(@RsHardDisk);
 
-     DRIVE_REMOTE:
 
-       Result := LoadResString(@RsRemoteDrive);
 
-     DRIVE_CDROM:
 
-       Result := LoadResString(@RsCDRomDrive);
 
-     DRIVE_RAMDISK:
 
-       Result := LoadResString(@RsRamDisk);
 
-     else
 
-       Result := LoadResString(@RsUnknownDrive);
 
-   end;
 
- end;
 
- function GetFileAgeCoherence(const FileName: string): Boolean;
 
- var
 
-   FileAttributesEx: WIN32_FILE_ATTRIBUTE_DATA;
 
- begin
 
-   Result := False;
 
-   if GetFileAttributesEx(PChar(FileName), GetFileExInfoStandard, @FileAttributesEx) then
 
-     {$IFDEF FPC}
 
-     Result := CompareFileTime(@FileAttributesEx.ftCreationTime, @FileAttributesEx.ftLastWriteTime) <= 0;
 
-     {$ELSE ~FPC}
 
-     Result := CompareFileTime(FileAttributesEx.ftCreationTime, FileAttributesEx.ftLastWriteTime) <= 0;
 
-     {$ENDIF ~FPC}
 
- end;
 
- {$ENDIF MSWINDOWS}
 
- procedure GetFileAttributeList(const Items: TStrings; const Attr: Integer);
 
- begin
 
-   { TODO : clear list? }
 
-   Assert(Assigned(Items));
 
-   if not Assigned(Items) then
 
-     Exit;
 
-   Items.BeginUpdate;
 
-   try
 
-     { TODO : differentiate Windows/UNIX idents }
 
-     if Attr and faDirectory = faDirectory then
 
-       Items.Add(LoadResString(@RsAttrDirectory));
 
-     if Attr and faReadOnly = faReadOnly then
 
-       Items.Add(LoadResString(@RsAttrReadOnly));
 
-     if Attr and faSysFile = faSysFile then
 
-       Items.Add(LoadResString(@RsAttrSystemFile));
 
-     if Attr and faArchive = faArchive then
 
-       Items.Add(LoadResString(@RsAttrArchive));
 
-     if Attr and faAnyFile = faAnyFile then
 
-       Items.Add(LoadResString(@RsAttrAnyFile));
 
-     if Attr and faHidden = faHidden then
 
-       Items.Add(LoadResString(@RsAttrHidden));
 
-   finally
 
-     Items.EndUpdate;
 
-   end;
 
- end;
 
- {$IFDEF MSWINDOWS}
 
- { TODO : GetFileAttributeListEx - Unix version }
 
- procedure GetFileAttributeListEx(const Items: TStrings; const Attr: Integer);
 
- begin
 
-   { TODO : clear list? }
 
-   Assert(Assigned(Items));
 
-   if not Assigned(Items) then
 
-     Exit;
 
-   Items.BeginUpdate;
 
-   try
 
-     if Attr and FILE_ATTRIBUTE_READONLY = FILE_ATTRIBUTE_READONLY then
 
-       Items.Add(LoadResString(@RsAttrReadOnly));
 
-     if Attr and FILE_ATTRIBUTE_HIDDEN = FILE_ATTRIBUTE_HIDDEN then
 
-       Items.Add(LoadResString(@RsAttrHidden));
 
-     if Attr and FILE_ATTRIBUTE_SYSTEM = FILE_ATTRIBUTE_SYSTEM then
 
-       Items.Add(LoadResString(@RsAttrSystemFile));
 
-     if Attr and FILE_ATTRIBUTE_DIRECTORY = FILE_ATTRIBUTE_DIRECTORY then
 
-       Items.Add(LoadResString(@RsAttrDirectory));
 
-     if Attr and FILE_ATTRIBUTE_ARCHIVE = FILE_ATTRIBUTE_ARCHIVE then
 
-       Items.Add(LoadResString(@RsAttrArchive));
 
-     if Attr and FILE_ATTRIBUTE_NORMAL = FILE_ATTRIBUTE_NORMAL then
 
-       Items.Add(LoadResString(@RsAttrNormal));
 
-     if Attr and FILE_ATTRIBUTE_TEMPORARY = FILE_ATTRIBUTE_TEMPORARY then
 
-       Items.Add(LoadResString(@RsAttrTemporary));
 
-     if Attr and FILE_ATTRIBUTE_COMPRESSED = FILE_ATTRIBUTE_COMPRESSED then
 
-       Items.Add(LoadResString(@RsAttrCompressed));
 
-     if Attr and FILE_ATTRIBUTE_OFFLINE = FILE_ATTRIBUTE_OFFLINE then
 
-       Items.Add(LoadResString(@RsAttrOffline));
 
-     if Attr and FILE_ATTRIBUTE_ENCRYPTED = FILE_ATTRIBUTE_ENCRYPTED then
 
-       Items.Add(LoadResString(@RsAttrEncrypted));
 
-     if Attr and FILE_ATTRIBUTE_REPARSE_POINT = FILE_ATTRIBUTE_REPARSE_POINT then
 
-       Items.Add(LoadResString(@RsAttrReparsePoint));
 
-     if Attr and FILE_ATTRIBUTE_SPARSE_FILE = FILE_ATTRIBUTE_SPARSE_FILE then
 
-       Items.Add(LoadResString(@RsAttrSparseFile));
 
-   finally
 
-     Items.EndUpdate;
 
-   end;
 
- end;
 
- {$ENDIF MSWINDOWS}
 
- function GetFileInformation(const FileName: string; out FileInfo: TSearchRec): Boolean;
 
- begin
 
-   Result := FindFirst(FileName, faAnyFile, FileInfo) = 0;
 
-   if Result then
 
-     {$IFDEF HAS_UNITSCOPE}System.{$ENDIF}SysUtils.FindClose(FileInfo);
 
- end;
 
- function GetFileInformation(const FileName: string): TSearchRec;
 
- begin
 
-   if not GetFileInformation(FileName, Result) then
 
-     RaiseLastOSError;
 
- end;
 
- {$IFDEF UNIX}
 
- { TODO -cHelp : Author: Robert Rossmair }
 
- function GetFileStatus(const FileName: string; out StatBuf: TStatBuf64;
 
-   const ResolveSymLinks: Boolean): Integer;
 
- begin
 
-   if ResolveSymLinks then
 
-     Result := stat64(PChar(FileName), StatBuf)
 
-   else
 
-     Result := lstat64(PChar(FileName), StatBuf);
 
- end;
 
- {$ENDIF UNIX}
 
- {$IFDEF MSWINDOWS}
 
- function GetFileLastWrite(const FileName: string): TFileTime;
 
- begin
 
-   Result := GetFileInformation(FileName).FindData.ftLastWriteTime;
 
- end;
 
- {$IFNDEF WINSCP}
 
- function GetFileLastWrite(const FileName: string; out LocalTime: TDateTime): Boolean;
 
- var
 
-   FileInfo: TSearchRec;
 
- begin
 
-   Result := GetFileInformation(FileName, FileInfo);
 
-   if Result then
 
-     LocalTime := FileTimeToLocalDateTime(FileInfo.FindData.ftLastWriteTime);
 
- end;
 
- {$ENDIF ~WINSCP}
 
- {$ENDIF MSWINDOWS}
 
- {$IFDEF UNIX}
 
- function GetFileLastWrite(const FileName: string; out TimeStamp: Integer; ResolveSymLinks: Boolean): Boolean;
 
- var
 
-   Buf: TStatBuf64;
 
- begin
 
-   Result := GetFileStatus(FileName, Buf, ResolveSymLinks) = 0;
 
-   if Result then
 
-     TimeStamp := Buf.st_mtime
 
- end;
 
- function GetFileLastWrite(const FileName: string; out LocalTime: TDateTime; ResolveSymLinks: Boolean): Boolean;
 
- var
 
-   Buf: TStatBuf64;
 
- begin
 
-   Result := GetFileStatus(FileName, Buf, ResolveSymLinks) = 0;
 
-   if Result then
 
-     LocalTime := FileDateToDateTime(Buf.st_mtime);
 
- end;
 
- function GetFileLastWrite(const FileName: string; ResolveSymLinks: Boolean): Integer;
 
- var
 
-   Buf: TStatBuf64;
 
- begin
 
-   if GetFileStatus(FileName, Buf, ResolveSymLinks) = 0 then
 
-     Result := Buf.st_mtime
 
-   else
 
-     Result := -1;
 
- end;
 
- {$ENDIF UNIX}
 
- {$IFDEF MSWINDOWS}
 
- function GetFileLastAccess(const FileName: string): TFileTime;
 
- begin
 
-   Result := GetFileInformation(FileName).FindData.ftLastAccessTime;
 
- end;
 
- {$IFNDEF WINSCP}
 
- function GetFileLastAccess(const FileName: string; out LocalTime: TDateTime): Boolean;
 
- var
 
-   FileInfo: TSearchRec;
 
- begin
 
-   Result := GetFileInformation(FileName, FileInfo);
 
-   if Result then
 
-     LocalTime := FileTimeToLocalDateTime(GetFileInformation(FileName).FindData.ftLastAccessTime);
 
- end;
 
- {$ENDIF ~WINSCP}
 
- {$ENDIF MSWINDOWS}
 
- {$IFDEF UNIX}
 
- function GetFileLastAccess(const FileName: string; out TimeStamp: Integer; ResolveSymLinks: Boolean): Boolean;
 
- var
 
-   Buf: TStatBuf64;
 
- begin
 
-   Result := GetFileStatus(FileName, Buf, ResolveSymLinks) = 0;
 
-   if Result then
 
-     TimeStamp := Buf.st_atime
 
- end;
 
- function GetFileLastAccess(const FileName: string; out LocalTime: TDateTime; ResolveSymLinks: Boolean): Boolean;
 
- var
 
-   Buf: TStatBuf64;
 
- begin
 
-   Result := GetFileStatus(FileName, Buf, ResolveSymLinks) = 0;
 
-   if Result then
 
-     LocalTime := FileDateToDateTime(Buf.st_atime);
 
- end;
 
- function GetFileLastAccess(const FileName: string; ResolveSymLinks: Boolean): Integer;
 
- var
 
-   Buf: TStatBuf64;
 
- begin
 
-   if GetFileStatus(FileName, Buf, ResolveSymLinks) = 0 then
 
-     Result := Buf.st_atime
 
-   else
 
-     Result := -1;
 
- end;
 
- {$ENDIF UNIX}
 
- {$IFDEF MSWINDOWS}
 
- function GetFileCreation(const FileName: string): TFileTime;
 
- begin
 
-   Result := GetFileInformation(FileName).FindData.ftCreationTime;
 
- end;
 
- {$IFNDEF WINSCP}
 
- function GetFileCreation(const FileName: string; out LocalTime: TDateTime): Boolean;
 
- var
 
-   FileInfo: TSearchRec;
 
- begin
 
-   Result := GetFileInformation(FileName, FileInfo);
 
-   if Result then
 
-     LocalTime := FileTimeToLocalDateTime(GetFileInformation(FileName).FindData.ftCreationTime);
 
- end;
 
- {$ENDIF ~WINSCP}
 
- {$ENDIF MSWINDOWS}
 
- {$IFDEF UNIX}
 
- function GetFileLastAttrChange(const FileName: string; out TimeStamp: Integer; ResolveSymLinks: Boolean): Boolean;
 
- var
 
-   Buf: TStatBuf64;
 
- begin
 
-   Result := GetFileStatus(FileName, Buf, ResolveSymLinks) = 0;
 
-   if Result then
 
-     TimeStamp := Buf.st_ctime
 
- end;
 
- function GetFileLastAttrChange(const FileName: string; out LocalTime: TDateTime; ResolveSymLinks: Boolean): Boolean;
 
- var
 
-   Buf: TStatBuf64;
 
- begin
 
-   Result := GetFileStatus(FileName, Buf, ResolveSymLinks) = 0;
 
-   if Result then
 
-     LocalTime := FileDateToDateTime(Buf.st_ctime);
 
- end;
 
- function GetFileLastAttrChange(const FileName: string; ResolveSymLinks: Boolean): Integer;
 
- var
 
-   Buf: TStatBuf64;
 
- begin
 
-   if GetFileStatus(FileName, Buf, ResolveSymLinks) = 0 then
 
-     Result := Buf.st_ctime
 
-   else
 
-     Result := -1;
 
- end;
 
- {$ENDIF UNIX}
 
- function GetModulePath(const Module: HMODULE): string;
 
- var
 
-   L: Integer;
 
- begin
 
-   L := MAX_PATH + 1;
 
-   SetLength(Result, L);
 
-   {$IFDEF MSWINDOWS}
 
-   L := {$IFDEF HAS_UNITSCOPE}Winapi.{$ENDIF}Windows.GetModuleFileName(Module, Pointer(Result), L);
 
-   {$ENDIF MSWINDOWS}
 
-   {$IFDEF UNIX}
 
-   {$IFDEF FPC}
 
-   L := 0; // FIXME
 
-   {$ELSE ~FPC}
 
-   L := GetModuleFileName(Module, Pointer(Result), L);
 
-   {$ENDIF ~FPC}
 
-   {$ENDIF UNIX}
 
-   SetLength(Result, L);
 
- end;
 
- function GetSizeOfFile(const FileName: string): Int64;
 
- {$IFDEF MSWINDOWS}
 
- var
 
-   FileAttributesEx: WIN32_FILE_ATTRIBUTE_DATA;
 
-   Size: TJclULargeInteger;
 
- begin
 
-   Result := 0;
 
-   if GetFileAttributesEx(PChar(FileName), GetFileExInfoStandard, @FileAttributesEx) then
 
-   begin
 
-     Size.LowPart := FileAttributesEx.nFileSizeLow;
 
-     Size.HighPart := FileAttributesEx.nFileSizeHigh;
 
-     Result := Size.QuadPart;
 
-   end
 
-   else
 
-     RaiseLastOSError;
 
- end;
 
- {$ENDIF MSWINDOWS}
 
- {$IFDEF UNIX}
 
- var
 
-   Buf: TStatBuf64;
 
- begin
 
-   if GetFileStatus(FileName, Buf, False) <> 0 then
 
-     RaiseLastOSError;
 
-   Result := Buf.st_size;
 
- end;
 
- {$ENDIF UNIX}
 
- {$IFDEF MSWINDOWS}
 
- function GetSizeOfFile(Handle: THandle): Int64; overload;
 
- var
 
-   Size: TJclULargeInteger;
 
- begin
 
-   Size.LowPart := GetFileSize(Handle, @Size.HighPart);
 
-   Result := Size.QuadPart;
 
- end;
 
- {$ENDIF MSWINDOWS}
 
- function GetSizeOfFile(const FileInfo: TSearchRec): Int64;
 
- {$IFDEF MSWINDOWS}
 
- begin
 
-   Int64Rec(Result).Lo := FileInfo.FindData.nFileSizeLow;
 
-   Int64Rec(Result).Hi := FileInfo.FindData.nFileSizeHigh;
 
- end;
 
- {$ENDIF MSWINDOWS}
 
- {$IFDEF UNIX}
 
- var
 
-   Buf: TStatBuf64;
 
- begin
 
-   // rr: Note that SysUtils.FindFirst/Next ignore files >= 2 GB under Linux,
 
-   //     thus the following code is rather pointless at the moment of this writing.
 
-   //     We apparently need to write our own set of Findxxx functions to overcome this limitation.
 
-   if GetFileStatus(FileInfo.PathOnly + FileInfo.Name, Buf, True) <> 0 then
 
-     Result := -1
 
-   else
 
-     Result := Buf.st_size
 
- end;
 
- {$ENDIF UNIX}
 
- {$IFDEF MSWINDOWS}
 
- {$IFDEF FPC}
 
- { TODO : Move this over to JclWin32 when JclWin32 gets overhauled. }
 
- function GetFileAttributesEx(lpFileName: PChar;
 
-   fInfoLevelId: TGetFileExInfoLevels; lpFileInformation: Pointer): BOOL; stdcall;
 
- external kernel32 name 'GetFileAttributesExA';
 
- {$ENDIF FPC}
 
- {$IFNDEF WINSCP}
 
- function GetStandardFileInfo(const FileName: string): TWin32FileAttributeData;
 
- var
 
-   Handle: THandle;
 
-   FileInfo: TByHandleFileInformation;
 
- begin
 
-   Assert(FileName <> '');
 
-   { TODO : Use RTDL-Version of GetFileAttributesEx }
 
-   if IsWin95 or IsWin95OSR2 or IsWinNT3 then
 
-   begin
 
-     Handle := CreateFile(PChar(FileName), GENERIC_READ, FILE_SHARE_READ, nil, OPEN_EXISTING, 0, 0);
 
-     if Handle <> INVALID_HANDLE_VALUE then
 
-     try
 
-       FileInfo.dwFileAttributes := 0;
 
-       if not GetFileInformationByHandle(Handle, FileInfo) then
 
-         raise EJclFileUtilsError.CreateResFmt(@RsFileUtilsAttrUnavailable, [FileName]);
 
-       Result.dwFileAttributes := FileInfo.dwFileAttributes;
 
-       Result.ftCreationTime := FileInfo.ftCreationTime;
 
-       Result.ftLastAccessTime := FileInfo.ftLastAccessTime;
 
-       Result.ftLastWriteTime := FileInfo.ftLastWriteTime;
 
-       Result.nFileSizeHigh := FileInfo.nFileSizeHigh;
 
-       Result.nFileSizeLow := FileInfo.nFileSizeLow;
 
-     finally
 
-       CloseHandle(Handle);
 
-     end
 
-     else
 
-       raise EJclFileUtilsError.CreateResFmt(@RsFileUtilsAttrUnavailable, [FileName]);
 
-   end
 
-   else
 
-   begin
 
-     if not GetFileAttributesEx(PChar(FileName), GetFileExInfoStandard, @Result) then
 
-       raise EJclFileUtilsError.CreateResFmt(@RsFileUtilsAttrUnavailable, [FileName]);
 
-   end;
 
- end;
 
- {$ENDIF}
 
- {$ENDIF MSWINDOWS}
 
- {$IFDEF MSWINDOWS}
 
- function IsDirectory(const FileName: string): Boolean;
 
- var
 
-   R: DWORD;
 
- begin
 
-   R := GetFileAttributes(PChar(FileName));
 
-   Result := (R <> DWORD(-1)) and ((R and FILE_ATTRIBUTE_DIRECTORY) <> 0);
 
- end;
 
- {$ENDIF MSWINDOWS}
 
- {$IFDEF UNIX}
 
- function IsDirectory(const FileName: string; ResolveSymLinks: Boolean): Boolean;
 
- var
 
-   Buf: TStatBuf64;
 
- begin
 
-   Result := False;
 
-   if GetFileStatus(FileName, Buf, ResolveSymLinks) = 0 then
 
-     Result := S_ISDIR(Buf.st_mode);
 
- end;
 
- {$ENDIF UNIX}
 
- function IsRootDirectory(const CanonicFileName: string): Boolean;
 
- {$IFDEF MSWINDOWS}
 
- var
 
-   I: Integer;
 
- begin
 
-   I := Pos(':\', CanonicFileName);
 
-   Result := (I > 0) and (I + 1 = Length(CanonicFileName));
 
- end;
 
- {$ENDIF MSWINDOWS}
 
- {$IFDEF UNIX}
 
- begin
 
-   Result := CanonicFileName = DirDelimiter;
 
- end;
 
- {$ENDIF UNIX}
 
- {$IFDEF MSWINDOWS}
 
- function LockVolume(const Volume: string; var Handle: THandle): Boolean;
 
- var
 
-   BytesReturned: DWORD;
 
- begin
 
-   Result := False;
 
-   Handle := CreateFile(PChar('\\.\' + Volume), GENERIC_READ or GENERIC_WRITE,
 
-     FILE_SHARE_READ or FILE_SHARE_WRITE, nil, OPEN_EXISTING,
 
-     FILE_FLAG_NO_BUFFERING, 0);
 
-   if Handle <> INVALID_HANDLE_VALUE then
 
-   begin
 
-     BytesReturned := 0;
 
-     Result := DeviceIoControl(Handle, FSCTL_LOCK_VOLUME, nil, 0, nil, 0,
 
-       BytesReturned, nil);
 
-     if not Result then
 
-     begin
 
-       CloseHandle(Handle);
 
-       Handle := INVALID_HANDLE_VALUE;
 
-     end;
 
-   end;
 
- end;
 
- function OpenVolume(const Drive: Char): THandle;
 
- var
 
-   VolumeName: array [0..6] of Char;
 
- begin
 
-   VolumeName := '\\.\A:';
 
-   VolumeName[4] := Drive;
 
-   Result := CreateFile(VolumeName, GENERIC_READ, FILE_SHARE_READ or FILE_SHARE_WRITE,
 
-     nil, OPEN_EXISTING, 0, 0);
 
- end;
 
- {$ENDIF MSWINDOWS}
 
- type
 
-   // indicates the file time to set, used by SetFileTimesHelper and SetDirTimesHelper
 
-   TFileTimes = (ftLastAccess, ftLastWrite {$IFDEF MSWINDOWS}, ftCreation {$ENDIF});
 
- {$IFDEF MSWINDOWS}
 
- function SetFileTimesHelper(const FileName: string; const DateTime: TDateTime; Times: TFileTimes): Boolean;
 
- var
 
-   Handle: THandle;
 
-   FileTime: TFileTime;
 
-   SystemTime: TSystemTime;
 
- begin
 
-   Result := False;
 
-   Handle := CreateFile(PChar(FileName), GENERIC_WRITE, FILE_SHARE_READ, nil,
 
-     OPEN_EXISTING, 0, 0);
 
-   if Handle <> INVALID_HANDLE_VALUE then
 
-   try
 
-     //SysUtils.DateTimeToSystemTime(DateTimeToLocalDateTime(DateTime), SystemTime);
 
-     {$IFDEF HAS_UNITSCOPE}System.{$ENDIF}SysUtils.DateTimeToSystemTime(DateTime, SystemTime);
 
-     FileTime.dwLowDateTime := 0;
 
-     FileTime.dwHighDateTime := 0;
 
-     if {$IFDEF HAS_UNITSCOPE}Winapi.{$ENDIF}Windows.SystemTimeToFileTime(SystemTime, FileTime) then
 
-     begin
 
-       case Times of
 
-         ftLastAccess:
 
-           Result := SetFileTime(Handle, nil, @FileTime, nil);
 
-         ftLastWrite:
 
-           Result := SetFileTime(Handle, nil, nil, @FileTime);
 
-         ftCreation:
 
-           Result := SetFileTime(Handle, @FileTime, nil, nil);
 
-       end;
 
-     end;
 
-   finally
 
-     CloseHandle(Handle);
 
-   end;
 
- end;
 
- {$ENDIF MSWINDOWS}
 
- {$IFDEF UNIX}
 
- function SetFileTimesHelper(const FileName: string; const DateTime: TDateTime; Times: TFileTimes): Boolean;
 
- var
 
-   FileTime: Integer;
 
-   StatBuf: TStatBuf64;
 
-   TimeBuf: utimbuf;
 
- begin
 
-   Result := False;
 
-   FileTime := DateTimeToFileDate(DateTime);
 
-   if GetFileStatus(FileName, StatBuf, False) = 0 then
 
-   begin
 
-     TimeBuf.actime := StatBuf.st_atime;
 
-     TimeBuf.modtime := StatBuf.st_mtime;
 
-     case Times of
 
-       ftLastAccess:
 
-         TimeBuf.actime := FileTime;
 
-       ftLastWrite:
 
-         TimeBuf.modtime := FileTime;
 
-     end;
 
-     Result := utime(PChar(FileName), @TimeBuf) = 0;
 
-   end;
 
- end;
 
- {$ENDIF UNIX}
 
- function SetFileLastAccess(const FileName: string; const DateTime: TDateTime): Boolean;
 
- begin
 
-   Result := SetFileTimesHelper(FileName, DateTime, ftLastAccess);
 
- end;
 
- function SetFileLastWrite(const FileName: string; const DateTime: TDateTime): Boolean;
 
- begin
 
-   Result := SetFileTimesHelper(FileName, DateTime, ftLastWrite);
 
- end;
 
- {$IFDEF MSWINDOWS}
 
- function SetFileCreation(const FileName: string; const DateTime: TDateTime): Boolean;
 
- begin
 
-   Result := SetFileTimesHelper(FileName, DateTime, ftCreation);
 
- end;
 
- // utility function for SetDirTimesHelper
 
- {$IFNDEF WINSCP}
 
- function BackupPrivilegesEnabled: Boolean;
 
- begin
 
-   Result := IsPrivilegeEnabled(SE_BACKUP_NAME) and IsPrivilegeEnabled(SE_RESTORE_NAME);
 
- end;
 
- function SetDirTimesHelper(const DirName: string; const DateTime: TDateTime;
 
-   Times: TFileTimes; RequireBackupRestorePrivileges: Boolean): Boolean;
 
- var
 
-   Handle: THandle;
 
-   FileTime: TFileTime;
 
-   SystemTime: TSystemTime;
 
- begin
 
-   Result := False;
 
-   if IsDirectory(DirName) and (not RequireBackupRestorePrivileges or BackupPrivilegesEnabled) then
 
-   begin
 
-     Handle := CreateFile(PChar(DirName), GENERIC_WRITE, FILE_SHARE_READ, nil,
 
-       OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, 0);
 
-     if Handle <> INVALID_HANDLE_VALUE then
 
-     try
 
-       {$IFDEF HAS_UNITSCOPE}System.{$ENDIF}SysUtils.DateTimeToSystemTime(DateTime, SystemTime);
 
-       FileTime.dwLowDateTime := 0;
 
-       FileTime.dwHighDateTime := 0;
 
-       {$IFDEF HAS_UNITSCOPE}Winapi.{$ENDIF}Windows.SystemTimeToFileTime(SystemTime, FileTime);
 
-       case Times of
 
-         ftLastAccess:
 
-           Result := SetFileTime(Handle, nil, @FileTime, nil);
 
-         ftLastWrite:
 
-           Result := SetFileTime(Handle, nil, nil, @FileTime);
 
-         ftCreation:
 
-           Result := SetFileTime(Handle, @FileTime, nil, nil);
 
-       end;
 
-     finally
 
-       CloseHandle(Handle);
 
-     end;
 
-   end;
 
- end;
 
- function SetDirLastWrite(const DirName: string; const DateTime: TDateTime; RequireBackupRestorePrivileges: Boolean = True): Boolean;
 
- begin
 
-   Result := SetDirTimesHelper(DirName, DateTime, ftLastWrite, RequireBackupRestorePrivileges);
 
- end;
 
- function SetDirLastAccess(const DirName: string; const DateTime: TDateTime; RequireBackupRestorePrivileges: Boolean = True): Boolean;
 
- begin
 
-   Result := SetDirTimesHelper(DirName, DateTime, ftLastAccess, RequireBackupRestorePrivileges);
 
- end;
 
- function SetDirCreation(const DirName: string; const DateTime: TDateTime; RequireBackupRestorePrivileges: Boolean = True): Boolean;
 
- begin
 
-   Result := SetDirTimesHelper(DirName, DateTime, ftCreation, RequireBackupRestorePrivileges);
 
- end;
 
- {$ENDIF ~WINSCP}
 
- procedure FillByteArray(var Bytes: array of Byte; Count: Cardinal; B: Byte);
 
- begin
 
-   FillMemory(@Bytes[0], Count, B);
 
- end;
 
- procedure ShredFile(const FileName: string; Times: Integer);
 
- const
 
-   BUFSIZE   = 4096;
 
-   ODD_FILL  = $C1;
 
-   EVEN_FILL = $3E;
 
- var
 
-   Fs: TFileStream;
 
-   Size: Integer;
 
-   N: Integer;
 
-   ContentPtr: array of Byte;
 
- begin
 
-   Size := FileGetSize(FileName);
 
-   if Size > 0 then
 
-   begin
 
-     if Times < 0 then
 
-       Times := 2
 
-     else
 
-       Times := Times * 2;
 
-     ContentPtr := nil;
 
-     Fs := TFileStream.Create(FileName, fmOpenReadWrite);
 
-     try
 
-       SetLength(ContentPtr, BUFSIZE);
 
-       while Times > 0 do
 
-       begin
 
-         if Times mod 2 = 0 then
 
-           FillByteArray(ContentPtr, BUFSIZE, EVEN_FILL)
 
-         else
 
-           FillByteArray(ContentPtr, BUFSIZE, ODD_FILL);
 
-         Fs.Seek(0, soBeginning);
 
-         N := Size div BUFSIZE;
 
-         while N > 0 do
 
-         begin
 
-           Fs.Write(ContentPtr[0], BUFSIZE);
 
-           Dec(N);
 
-         end;
 
-         N := Size mod BUFSIZE;
 
-         if N > 0 then
 
-           Fs.Write(ContentPtr[0], N);
 
-         FlushFileBuffers(Fs.Handle);
 
-         Dec(Times);
 
-       end;
 
-     finally
 
-       ContentPtr := nil;
 
-       Fs.Free;
 
-       DeleteFile(FileName);
 
-     end;
 
-   end
 
-   else
 
-     DeleteFile(FileName);
 
- end;
 
- function UnlockVolume(var Handle: THandle): Boolean;
 
- var
 
-   BytesReturned: DWORD;
 
- begin
 
-   Result := False;
 
-   if Handle <> INVALID_HANDLE_VALUE then
 
-   begin
 
-     BytesReturned := 0;
 
-     Result := DeviceIoControl(Handle, FSCTL_UNLOCK_VOLUME, nil, 0, nil, 0,
 
-       BytesReturned, nil);
 
-     if Result then
 
-     begin
 
-       CloseHandle(Handle);
 
-       Handle := INVALID_HANDLE_VALUE;
 
-     end;
 
-   end;
 
- end;
 
- {$ENDIF MSWINDOWS}
 
- {$IFDEF UNIX}
 
- function CreateSymbolicLink(const Name, Target: string): Boolean;
 
- begin
 
-   Result := symlink(PChar(Target), PChar(Name)) = 0;
 
- end;
 
- function SymbolicLinkTarget(const Name: string): string;
 
- var
 
-   N, BufLen: Integer;
 
- begin
 
-   BufLen := 128;
 
-   repeat
 
-     Inc(BufLen, BufLen);
 
-     SetLength(Result, BufLen);
 
-     N := readlink(PChar(Name), PChar(Result), BufLen);
 
-     if N < 0 then // Error
 
-     begin
 
-       Result := '';
 
-       Exit;
 
-     end;
 
-   until N < BufLen;
 
-   SetLength(Result, N);
 
- end;
 
- {$ENDIF UNIX}
 
- //=== File Version info routines =============================================
 
- {$IFDEF MSWINDOWS}
 
- const
 
-   VerKeyNames: array [1..12] of string =
 
-    ('Comments',
 
-     'CompanyName',
 
-     'FileDescription',
 
-     'FileVersion',
 
-     'InternalName',
 
-     'LegalCopyright',
 
-     'LegalTradeMarks',
 
-     'OriginalFilename',
 
-     'ProductName',
 
-     'ProductVersion',
 
-     'SpecialBuild',
 
-     'PrivateBuild');
 
- function OSIdentToString(const OSIdent: DWORD): string;
 
- begin
 
-   case OSIdent of
 
-     VOS_UNKNOWN:
 
-       Result := LoadResString(@RsVosUnknown);
 
-     VOS_DOS:
 
-       Result := LoadResString(@RsVosDos);
 
-     VOS_OS216:
 
-       Result := LoadResString(@RsVosOS216);
 
-     VOS_OS232:
 
-       Result := LoadResString(@RsVosOS232);
 
-     VOS_NT:
 
-       Result := LoadResString(@RsVosNT);
 
-     VOS__WINDOWS16:
 
-       Result := LoadResString(@RsVosWindows16);
 
-     VOS__PM16:
 
-       Result := LoadResString(@RsVosPM16);
 
-     VOS__PM32:
 
-       Result := LoadResString(@RsVosPM32);
 
-     VOS__WINDOWS32:
 
-       Result := LoadResString(@RsVosWindows32);
 
-     VOS_DOS_WINDOWS16:
 
-       Result := LoadResString(@RsVosDosWindows16);
 
-     VOS_DOS_WINDOWS32:
 
-       Result := LoadResString(@RsVosDosWindows32);
 
-     VOS_OS216_PM16:
 
-       Result := LoadResString(@RsVosOS216PM16);
 
-     VOS_OS232_PM32:
 
-       Result := LoadResString(@RsVosOS232PM32);
 
-     VOS_NT_WINDOWS32:
 
-       Result := LoadResString(@RsVosNTWindows32);
 
-   else
 
-     Result := '';
 
-   end;
 
-   if Result = '' then
 
-     Result := LoadResString(@RsVosUnknown)
 
-   else
 
-     Result := Format(LoadResString(@RsVosDesignedFor), [Result]);
 
- end;
 
- function OSFileTypeToString(const OSFileType: DWORD; const OSFileSubType: DWORD): string;
 
- begin
 
-   case OSFileType of
 
-     VFT_UNKNOWN:
 
-       Result := LoadResString(@RsVftUnknown);
 
-     VFT_APP:
 
-       Result := LoadResString(@RsVftApp);
 
-     VFT_DLL:
 
-       Result := LoadResString(@RsVftDll);
 
-     VFT_DRV:
 
-       begin
 
-         case OSFileSubType of
 
-           VFT2_DRV_PRINTER:
 
-             Result := LoadResString(@RsVft2DrvPRINTER);
 
-           VFT2_DRV_KEYBOARD:
 
-             Result := LoadResString(@RsVft2DrvKEYBOARD);
 
-           VFT2_DRV_LANGUAGE:
 
-             Result := LoadResString(@RsVft2DrvLANGUAGE);
 
-           VFT2_DRV_DISPLAY:
 
-             Result := LoadResString(@RsVft2DrvDISPLAY);
 
-           VFT2_DRV_MOUSE:
 
-             Result := LoadResString(@RsVft2DrvMOUSE);
 
-           VFT2_DRV_NETWORK:
 
-             Result := LoadResString(@RsVft2DrvNETWORK);
 
-           VFT2_DRV_SYSTEM:
 
-             Result := LoadResString(@RsVft2DrvSYSTEM);
 
-           VFT2_DRV_INSTALLABLE:
 
-             Result := LoadResString(@RsVft2DrvINSTALLABLE);
 
-           VFT2_DRV_SOUND:
 
-             Result := LoadResString(@RsVft2DrvSOUND);
 
-           VFT2_DRV_COMM:
 
-             Result := LoadResString(@RsVft2DrvCOMM);
 
-         else
 
-           Result := '';
 
-         end;
 
-         Result := Result + ' ' + LoadResString(@RsVftDrv);
 
-       end;
 
-     VFT_FONT:
 
-       begin
 
-         case OSFileSubType of
 
-           VFT2_FONT_RASTER:
 
-             Result := LoadResString(@RsVft2FontRASTER);
 
-           VFT2_FONT_VECTOR:
 
-             Result := LoadResString(@RsVft2FontVECTOR);
 
-           VFT2_FONT_TRUETYPE:
 
-             Result := LoadResString(@RsVft2FontTRUETYPE);
 
-         else
 
-           Result := '';
 
-         end;
 
-         Result := Result + ' ' + LoadResString(@RsVftFont);
 
-       end;
 
-     VFT_VXD:
 
-       Result := LoadResString(@RsVftVxd);
 
-     VFT_STATIC_LIB:
 
-       Result := LoadResString(@RsVftStaticLib);
 
-   else
 
-     Result := '';
 
-   end;
 
-   Result := TrimLeft(Result);
 
- end;
 
- function VersionResourceAvailable(const FileName: string): Boolean;
 
- var
 
-   Size: DWORD;
 
-   Handle: DWORD;
 
-   Buffer: string;
 
- begin
 
-   Result := False;
 
-   Handle := 0;
 
-   Size := GetFileVersionInfoSize(PChar(FileName), Handle);
 
-   if Size > 0 then
 
-   begin
 
-     SetLength(Buffer, Size);
 
-     Result := GetFileVersionInfo(PChar(FileName), Handle, Size, PChar(Buffer));
 
-   end;
 
- end;
 
- function VersionResourceAvailable(const Window: HWND): Boolean;
 
- begin
 
-   Result := VersionResourceAvailable(WindowToModuleFileName(Window));
 
- end;
 
- function VersionResourceAvailable(const Module: HMODULE): Boolean;
 
- begin
 
-   if Module <> 0 then
 
-     Result :=VersionResourceAvailable(GetModulePath(Module))
 
-   else
 
-     raise EJclError.CreateResFmt(@RsEModuleNotValid, [Module]);
 
- end;
 
- function WindowToModuleFileName(const Window: HWND): string;
 
- type
 
-   {$IFDEF SUPPORTS_UNICODE}
 
-   TGetModuleFileNameEx = function(hProcess: THandle; hModule: HMODULE; FileName: PWideChar; nSize: DWORD): DWORD; stdcall;
 
-   TQueryFullProcessImageName = function(HProcess: THandle; dwFlags: DWORD; lpExeName: PWideChar; lpdwSize: PDWORD): BOOL; stdcall;
 
-   {$ELSE ~SUPPORTS_UNICODE}
 
-   TGetModuleFileNameEx = function(hProcess: THandle; hModule: HMODULE; FileName: PAnsiChar; nSize: DWORD): DWORD; stdcall;
 
-   TQueryFullProcessImageName = function(HProcess: THandle; dwFlags: DWORD; lpExeName: PAnsiChar; lpdwSize: PDWORD): BOOL; stdcall;
 
-   {$ENDIF ~SUPPORTS_UNICODE}
 
- var
 
-   FileName: array[0..300] of Char;
 
-   DllHinst: HMODULE;
 
-   ProcessID: DWORD;
 
-   HProcess: THandle;
 
-   GetModuleFileNameExAddress: TGetModuleFileNameEx;
 
-   QueryFullProcessImageNameAddress: TQueryFullProcessImageName;
 
-   Len: DWORD;
 
- begin
 
-   Result := '';
 
-   if Window <> 0 then
 
-   begin
 
-     if not JclCheckWinVersion(5, 0) then // Win2k or newer required
 
-       raise EJclWin32Error.CreateRes(@RsEWindowsVersionNotSupported);
 
-     {$IFDEF HAS_UNITSCOPE}Winapi.{$ENDIF}Windows.GetWindowThreadProcessId(Window, @ProcessID);
 
-     hProcess := {$IFDEF HAS_UNITSCOPE}Winapi.{$ENDIF}Windows.OpenProcess(PROCESS_QUERY_INFORMATION or PROCESS_VM_READ, false, ProcessID);
 
-     if hProcess <> 0 then
 
-     begin
 
-       try
 
-         if JclCheckWinVersion(6, 0) then // WinVista or newer
 
-         begin
 
-           DllHinst := LoadLibrary('Kernel32.dll');
 
-           if DllHinst <> 0 then
 
-           begin
 
-             try
 
-               {$IFDEF SUPPORTS_UNICODE}
 
-               QueryFullProcessImageNameAddress := GetProcAddress(DllHinst, 'QueryFullProcessImageNameW');
 
-               {$ELSE ~SUPPORTS_UNICODE}
 
-               QueryFullProcessImageNameAddress := GetProcAddress(DllHinst, 'QueryFullProcessImageNameA');
 
-               {$ENDIF ~SUPPORTS_UNICODE}
 
-               if Assigned(QueryFullProcessImageNameAddress) then
 
-               begin
 
-                 Len := Length(FileName);
 
-                 if QueryFullProcessImageNameAddress(hProcess, 0, FileName, PDWORD(@Len)) then
 
-                   Result := FileName;
 
-                 //else
 
-                 //  RaiseLastOSError   would be nice, but it didn't raise an exception before the return value was checked
 
-               end
 
-               else
 
-                 raise EJclError.CreateResFmt(@RsEFunctionNotFound, ['Kernel32.dll', 'QueryFullProcessImageName']);
 
-             finally
 
-               FreeLibrary(DllHinst);
 
-             end;
 
-           end
 
-           else
 
-             raise EJclError.CreateResFmt(@RsELibraryNotFound, ['Kernel32.dll']);
 
-         end
 
-         else
 
-         begin
 
-           DllHinst := LoadLibrary('Psapi.dll');
 
-           if DllHinst <> 0 then
 
-           begin
 
-             try
 
-               {$IFDEF SUPPORTS_UNICODE}
 
-               GetModuleFileNameExAddress := GetProcAddress(DllHinst, 'GetModuleFileNameExW');
 
-               {$ELSE ~SUPPORTS_UNICODE}
 
-               GetModuleFileNameExAddress := GetProcAddress(DllHinst, 'GetModuleFileNameExA');
 
-               {$ENDIF ~SUPPORTS_UNICODE}
 
-               if Assigned(GetModuleFileNameExAddress) then
 
-               begin
 
-                 Len := GetModuleFileNameExAddress(hProcess, 0, FileName, Length(FileName));
 
-                 if Len > 0 then
 
-                   Result := FileName;
 
-                 //else
 
-                 //  RaiseLastOSError;   would be nice, but it didn't raise an exception before the return value was checked
 
-               end
 
-               else
 
-                 raise EJclError.CreateResFmt(@RsEFunctionNotFound, ['Psapi.dll', 'GetModuleFileNameEx']);
 
-             finally
 
-               FreeLibrary(DllHinst);
 
-             end;
 
-           end
 
-           else
 
-             raise EJclError.CreateResFmt(@RsELibraryNotFound, ['Psapi.dll']);
 
-         end;
 
-       finally
 
-         CloseHandle(hProcess);
 
-       end;
 
-     end
 
-     else
 
-       raise EJclError.CreateResFmt(@RsEProcessNotValid, [ProcessID]);
 
-   end
 
-   else
 
-     raise EJclError.CreateResFmt(@RsEWindowNotValid, [Window]);
 
- end;
 
- {$ENDIF MSWINDOWS}
 
- // Version Info formatting
 
- function FormatVersionString(const HiV, LoV: Word): string;
 
- begin
 
-   Result := Format('%u.%.2u', [HiV, LoV]);
 
- end;
 
- function FormatVersionString(const Major, Minor, Build, Revision: Word): string;
 
- begin
 
-   Result := Format('%u.%u.%u.%u', [Major, Minor, Build, Revision]);
 
- end;
 
- {$IFDEF MSWINDOWS}
 
- function FormatVersionString(const FixedInfo: TVSFixedFileInfo; VersionFormat: TFileVersionFormat): string;
 
- begin
 
-   case VersionFormat of
 
-     vfMajorMinor:
 
-       Result := Format('%u.%u', [HiWord(FixedInfo.dwFileVersionMS), LoWord(FixedInfo.dwFileVersionMS)]);
 
-     vfFull:
 
-       Result := Format('%u.%u.%u.%u', [HiWord(FixedInfo.dwFileVersionMS), LoWord(FixedInfo.dwFileVersionMS),
 
-         HiWord(FixedInfo.dwFileVersionLS), LoWord(FixedInfo.dwFileVersionLS)]);
 
-   end;
 
- end;
 
- // Version Info extracting
 
- procedure VersionExtractFileInfo(const FixedInfo: TVSFixedFileInfo; var Major, Minor, Build, Revision: Word);
 
- begin
 
-   Major := HiWord(FixedInfo.dwFileVersionMS);
 
-   Minor := LoWord(FixedInfo.dwFileVersionMS);
 
-   Build := HiWord(FixedInfo.dwFileVersionLS);
 
-   Revision := LoWord(FixedInfo.dwFileVersionLS);
 
- end;
 
- procedure VersionExtractProductInfo(const FixedInfo: TVSFixedFileInfo; var Major, Minor, Build, Revision: Word);
 
- begin
 
-   Major := HiWord(FixedInfo.dwProductVersionMS);
 
-   Minor := LoWord(FixedInfo.dwProductVersionMS);
 
-   Build := HiWord(FixedInfo.dwProductVersionLS);
 
-   Revision := LoWord(FixedInfo.dwProductVersionLS);
 
- end;
 
- // Fixed Version Info routines
 
- function VersionFixedFileInfo(const FileName: string; var FixedInfo: TVSFixedFileInfo): Boolean;
 
- var
 
-   Size, FixInfoLen: DWORD;
 
-   Handle: DWORD;
 
-   Buffer: string;
 
-   FixInfoBuf: PVSFixedFileInfo;
 
- begin
 
-   Result := False;
 
-   Handle := 0;
 
-   Size := GetFileVersionInfoSize(PChar(FileName), Handle);
 
-   if Size > 0 then
 
-   begin
 
-     SetLength(Buffer, Size);
 
-     FixInfoLen := 0;
 
-     FixInfoBuf := nil;
 
-     if GetFileVersionInfo(PChar(FileName), Handle, Size, Pointer(Buffer)) and
 
-       VerQueryValue(Pointer(Buffer), DirDelimiter, Pointer(FixInfoBuf), FixInfoLen) and
 
-       (FixInfoLen = SizeOf(TVSFixedFileInfo)) then
 
-     begin
 
-       Result := True;
 
-       FixedInfo := FixInfoBuf^;
 
-     end;
 
-   end;
 
- end;
 
- function VersionFixedFileInfoString(const FileName: string; VersionFormat: TFileVersionFormat;
 
-   const NotAvailableText: string): string;
 
- var
 
-   FixedInfo: TVSFixedFileInfo;
 
- begin
 
-   FixedInfo.dwSignature := 0;
 
-   if VersionFixedFileInfo(FileName, FixedInfo) then
 
-     Result := FormatVersionString(FixedInfo, VersionFormat)
 
-   else
 
-     Result := NotAvailableText;
 
- end;
 
- //=== { TJclFileVersionInfo } ================================================
 
- constructor TJclFileVersionInfo.Attach(VersionInfoData: Pointer; Size: Integer);
 
- begin
 
-   SetLength(FBuffer, Size);
 
-   CopyMemory(PAnsiChar(FBuffer), VersionInfoData, Size);
 
-   ExtractData;
 
- end;
 
- constructor TJclFileVersionInfo.Create(const FileName: string);
 
- var
 
-   Handle: DWORD;
 
-   Size: DWORD;
 
- begin
 
-   if not FileExists(FileName) then
 
-     raise EJclFileVersionInfoError.CreateResFmt(@RsFileUtilsFileDoesNotExist, [FileName]);
 
-   Handle := 0;
 
-   Size := GetFileVersionInfoSize(PChar(FileName), Handle);
 
-   if Size = 0 then
 
-     raise EJclFileVersionInfoError.CreateRes(@RsFileUtilsNoVersionInfo);
 
-   SetLength(FBuffer, Size);
 
-   Win32Check(GetFileVersionInfo(PChar(FileName), Handle, Size, PAnsiChar(FBuffer)));
 
-   ExtractData;
 
- end;
 
- {$IFDEF MSWINDOWS}
 
- {$IFDEF FPC}
 
- constructor TJclFileVersionInfo.Create(const Window: HWND; Dummy: Pointer = nil);
 
- {$ELSE}
 
- constructor TJclFileVersionInfo.Create(const Window: HWND);
 
- {$ENDIF}
 
- begin
 
-   Create(WindowToModuleFileName(Window));
 
- end;
 
- constructor TJclFileVersionInfo.Create(const Module: HMODULE);
 
- begin
 
-   if Module <> 0 then
 
-     Create(GetModulePath(Module))
 
-   else
 
-     raise EJclError.CreateResFmt(@RsEModuleNotValid, [Module]);
 
- end;
 
- {$ENDIF MSWINDOWS}
 
- destructor TJclFileVersionInfo.Destroy;
 
- begin
 
-   FreeAndNil(FItemList);
 
-   FreeAndNil(FItems);
 
-   inherited Destroy;
 
- end;
 
- class function TJclFileVersionInfo.FileHasVersionInfo(const FileName: string): boolean;
 
- var
 
-   Dummy: DWord;
 
- begin
 
-   Result := GetFileVersionInfoSize(PChar(FileName), Dummy) <> 0;
 
- end;
 
- procedure TJclFileVersionInfo.CheckLanguageIndex(Value: Integer);
 
- begin
 
-   if (Value < 0) or (Value >= LanguageCount) then
 
-     raise EJclFileVersionInfoError.CreateRes(@RsFileUtilsLanguageIndex);
 
- end;
 
- procedure TJclFileVersionInfo.CreateItemsForLanguage;
 
- var
 
-   I: Integer;
 
- begin
 
-   Items.Clear;
 
-   for I := 0 to FItemList.Count - 1 do
 
-     if Integer(FItemList.Objects[I]) = FLanguageIndex then
 
-       Items.AddObject(FItemList[I], Pointer(FLanguages[FLanguageIndex].Pair));
 
- end;
 
- procedure TJclFileVersionInfo.ExtractData;
 
- var
 
-   Data, EndOfData: PAnsiChar;
 
-   Len, ValueLen, DataType: Word;
 
-   HeaderSize: Integer;
 
-   Key: string;
 
-   Error, IsUnicode: Boolean;
 
-   procedure Padding(var DataPtr: PAnsiChar);
 
-   begin
 
-     while TJclAddr(DataPtr) and 3 <> 0 do
 
-       Inc(DataPtr);
 
-   end;
 
-   procedure GetHeader;
 
-   var
 
-     P: PAnsiChar;
 
-     TempKey: PWideChar;
 
-   begin
 
-     Key := '';
 
-     P := Data;
 
-     Len := PWord(P)^;
 
-     if Len = 0 then
 
-     begin
 
-       // do not raise error in the case of resources padded with 0
 
-       while P < EndOfData do
 
-       begin
 
-         Error := P^ <> #0;
 
-         if Error then
 
-           Break;
 
-         Inc(P);
 
-       end;
 
-       Exit;
 
-     end;
 
-     Inc(P, SizeOf(Word));
 
-     ValueLen := PWord(P)^;
 
-     Inc(P, SizeOf(Word));
 
-     if IsUnicode then
 
-     begin
 
-       DataType := PWord(P)^;
 
-       Inc(P, SizeOf(Word));
 
-       TempKey := PWideChar(P);
 
-       Inc(P, (lstrlenW(TempKey) + 1) * SizeOf(WideChar)); // length + #0#0
 
-       Key := TempKey;
 
-     end
 
-     else
 
-     begin
 
-       DataType := 1;
 
-       Key := string(PAnsiChar(P));
 
-       Inc(P, lstrlenA(PAnsiChar(P)) + 1);
 
-     end;
 
-     Padding(P);
 
-     HeaderSize := P - Data;
 
-     Data := P;
 
-   end;
 
-   procedure FixKeyValue;
 
-   const
 
-     HexNumberCPrefix = '0x';
 
-   var
 
-     I: Integer;
 
-   begin // GAPI32.DLL version 5.5.2803.1 contanins '04050x04E2' value
 
-     repeat
 
-       I := Pos(HexNumberCPrefix, Key);
 
-       if I > 0 then
 
-         Delete(Key, I, Length(HexNumberCPrefix));
 
-     until I = 0;
 
-     I := 1;
 
-     while I <= Length(Key) do
 
-       if CharIsHexDigit(Key[I]) then
 
-         Inc(I)
 
-       else
 
-         Delete(Key, I, 1);
 
-     // Office16\1031\GrooveIntlResource.dll contains a '4094B0' key. Both parts (lang and codepage)
 
-     // are missing their leading zero. It should have been '040904B0'.
 
-     // The Windows file property dialog falls back to "English (United States) 1252", so do we.
 
-     if Length(Key) < 8 then
 
-       Key := '040904E4';
 
-   end;
 
-   procedure ProcessStringInfo(Size: Integer);
 
-   var
 
-     EndPtr, EndStringPtr: PAnsiChar;
 
-     LangIndex: Integer;
 
-     LangIdRec: TLangIdRec;
 
-     Value: string;
 
-   begin
 
-     EndPtr := Data + Size;
 
-     LangIndex := 0;
 
-     while not Error and (Data < EndPtr) do
 
-     begin
 
-       GetHeader; // StringTable
 
-       FixKeyValue;
 
-       if (ValueLen <> 0) or (Length(Key) <> 8) then
 
-       begin
 
-         Error := True;
 
-         Break;
 
-       end;
 
-       Padding(Data);
 
-       LangIdRec.LangId := StrToIntDef('$' + Copy(Key, 1, 4), 0);
 
-       LangIdRec.CodePage := StrToIntDef('$' + Copy(Key, 5, 4), 0);
 
-       SetLength(FLanguages, LangIndex + 1);
 
-       FLanguages[LangIndex] := LangIdRec;
 
-       EndStringPtr := Data + Len - HeaderSize;
 
-       while not Error and (Data < EndStringPtr) do
 
-       begin
 
-         GetHeader; // string
 
-         case DataType of
 
-           0:
 
-             if ValueLen in [1..4] then
 
-               Value := Format('$%.*x', [ValueLen * 2, PInteger(Data)^])
 
-             else
 
-             begin
 
-               if (ValueLen > 0) and IsUnicode then
 
-                 Value:=PWideChar(Data)
 
-               else
 
-                 Value := '';
 
-             end;
 
-           1:
 
-             if ValueLen = 0 then
 
-               Value := ''
 
-             else
 
-             if IsUnicode then
 
-             begin
 
-               Value := WideCharLenToString(PWideChar(Data), ValueLen);
 
-               StrResetLength(Value);
 
-             end
 
-             else
 
-               Value := string(PAnsiChar(Data));
 
-         else
 
-           Error := True;
 
-           Break;
 
-         end;
 
-         Inc(Data, Len - HeaderSize);
 
-         Padding(Data); // String.Padding
 
-         FItemList.AddObject(Format('%s=%s', [Key, Value]), Pointer(LangIndex));
 
-       end;
 
-       Inc(LangIndex);
 
-     end;
 
-   end;
 
-   procedure ProcessVarInfo;
 
-   var
 
-     TranslationIndex: Integer;
 
-   begin
 
-     GetHeader; // Var
 
-     if SameText(Key, 'Translation') then
 
-     begin
 
-       SetLength(FTranslations, ValueLen div SizeOf(TLangIdRec));
 
-       for TranslationIndex := 0 to Length(FTranslations) - 1 do
 
-       begin
 
-         FTranslations[TranslationIndex] := PLangIdRec(Data)^;
 
-         Inc(Data, SizeOf(TLangIdRec));
 
-       end;
 
-     end;
 
-   end;
 
- begin
 
-   FItemList := TStringList.Create;
 
-   FItems := TStringList.Create;
 
-   Data := Pointer(FBuffer);
 
-   Assert(TJclAddr(Data) mod 4 = 0);
 
-   IsUnicode := (PWord(Data + 4)^ in [0, 1]);
 
-   Error := True;
 
-   GetHeader;
 
-   EndOfData := Data + Len - HeaderSize;
 
-   if SameText(Key, 'VS_VERSION_INFO') and (ValueLen = SizeOf(TVSFixedFileInfo)) then
 
-   begin
 
-     FFixedInfo := PVSFixedFileInfo(Data);
 
-     Error := FFixedInfo.dwSignature <> $FEEF04BD;
 
-     Inc(Data, ValueLen); // VS_FIXEDFILEINFO
 
-     Padding(Data);       // VS_VERSIONINFO.Padding2
 
-     while not Error and (Data < EndOfData) do
 
-     begin
 
-       GetHeader;
 
-       Inc(Data, ValueLen); // some files (VREDIR.VXD 4.00.1111) has non zero value of ValueLen
 
-       Dec(Len, HeaderSize + ValueLen);
 
-       if SameText(Key, 'StringFileInfo') then
 
-         ProcessStringInfo(Len)
 
-       else
 
-       if SameText(Key, 'VarFileInfo') then
 
-         ProcessVarInfo
 
-       else
 
-         Break;
 
-     end;
 
-     ExtractFlags;
 
-     CreateItemsForLanguage;
 
-   end;
 
-   if Error then
 
-     raise EJclFileVersionInfoError.CreateRes(@RsFileUtilsNoVersionInfo);
 
- end;
 
- procedure TJclFileVersionInfo.ExtractFlags;
 
- var
 
-   Masked: DWORD;
 
- begin
 
-   FFileFlags := [];
 
-   Masked := FFixedInfo^.dwFileFlags and FFixedInfo^.dwFileFlagsMask;
 
-   if (Masked and VS_FF_DEBUG) <> 0 then
 
-     Include(FFileFlags, ffDebug);
 
-   if (Masked and VS_FF_INFOINFERRED) <> 0 then
 
-     Include(FFileFlags, ffInfoInferred);
 
-   if (Masked and VS_FF_PATCHED) <> 0 then
 
-     Include(FFileFlags, ffPatched);
 
-   if (Masked and VS_FF_PRERELEASE) <> 0 then
 
-     Include(FFileFlags, ffPreRelease);
 
-   if (Masked and VS_FF_PRIVATEBUILD) <> 0 then
 
-     Include(FFileFlags, ffPrivateBuild);
 
-   if (Masked and VS_FF_SPECIALBUILD) <> 0 then
 
-     Include(FFileFlags, ffSpecialBuild);
 
- end;
 
- function TJclFileVersionInfo.GetBinFileVersion: string;
 
- begin
 
-   Result := Format('%u.%u.%u.%u', [HiWord(FFixedInfo^.dwFileVersionMS),
 
-     LoWord(FFixedInfo^.dwFileVersionMS), HiWord(FFixedInfo^.dwFileVersionLS),
 
-     LoWord(FFixedInfo^.dwFileVersionLS)]);
 
- end;
 
- function TJclFileVersionInfo.GetBinProductVersion: string;
 
- begin
 
-   Result := Format('%u.%u.%u.%u', [HiWord(FFixedInfo^.dwProductVersionMS),
 
-     LoWord(FFixedInfo^.dwProductVersionMS), HiWord(FFixedInfo^.dwProductVersionLS),
 
-     LoWord(FFixedInfo^.dwProductVersionLS)]);
 
- end;
 
- function TJclFileVersionInfo.GetCustomFieldValue(const FieldName: string): string;
 
- var
 
-   ItemIndex: Integer;
 
- begin
 
-   if FieldName <> '' then
 
-   begin
 
-     ItemIndex := FItems.IndexOfName(FieldName);
 
-     if ItemIndex <> -1 then
 
-       //Return the required value, the value the user passed in was found.
 
-       Result := FItems.Values[FieldName]
 
-     else
 
-       raise EJclFileVersionInfoError.CreateResFmt(@RsFileUtilsValueNotFound, [FieldName]);
 
-   end
 
-   else
 
-     raise EJclFileVersionInfoError.CreateRes(@RsFileUtilsEmptyValue);
 
- end;
 
- function TJclFileVersionInfo.GetFileOS: DWORD;
 
- begin
 
-   Result := FFixedInfo^.dwFileOS;
 
- end;
 
- function TJclFileVersionInfo.GetFileSubType: DWORD;
 
- begin
 
-   Result := FFixedInfo^.dwFileSubtype;
 
- end;
 
- function TJclFileVersionInfo.GetFileType: DWORD;
 
- begin
 
-   Result := FFixedInfo^.dwFileType;
 
- end;
 
- function TJclFileVersionInfo.GetFileVersionBuild: string;
 
- var
 
-   Left: Integer;
 
- begin
 
-   Result := FileVersion;
 
-   StrReplaceChar(Result, ',', '.');
 
-   Left := CharLastPos(Result, '.') + 1;
 
-   Result := StrMid(Result, Left, Length(Result) - Left + 1);
 
-   Result := Trim(Result);
 
- end;
 
- function TJclFileVersionInfo.GetFileVersionMajor: string;
 
- begin
 
-   Result := FileVersion;
 
-   StrReplaceChar(Result, ',', '.');
 
-   Result := StrBefore('.', Result);
 
-   Result := Trim(Result);
 
- end;
 
- function TJclFileVersionInfo.GetFileVersionMinor: string;
 
- var
 
-   Left, Right: integer;
 
- begin
 
-   Result := FileVersion;
 
-   StrReplaceChar(Result, ',', '.');
 
-   Left := CharPos(Result, '.') + 1;           // skip major
 
-   Right := CharPos(Result, '.', Left) {-1};
 
-   Result := StrMid(Result, Left, Right - Left {+1});
 
-   Result := Trim(Result);
 
- end;
 
- function TJclFileVersionInfo.GetFileVersionRelease: string;
 
- var
 
-   Left, Right: Integer;
 
- begin
 
-   Result := FileVersion;
 
-   StrReplaceChar(Result, ',', '.');
 
-   Left := CharPos(Result, '.') + 1;           // skip major
 
-   Left := CharPos(Result, '.', Left) + 1;     // skip minor
 
-   Right := CharPos(Result, '.', Left) {-1};
 
-   Result := StrMid(Result, Left, Right - Left {+1});
 
-   Result := Trim(Result);
 
- end;
 
- function TJclFileVersionInfo.GetFixedInfo: TVSFixedFileInfo;
 
- begin
 
-   Result := FFixedInfo^;
 
- end;
 
- function TJclFileVersionInfo.GetItems: TStrings;
 
- begin
 
-   Result := FItems;
 
- end;
 
- function TJclFileVersionInfo.GetLanguageCount: Integer;
 
- begin
 
-   Result := Length(FLanguages);
 
- end;
 
- function TJclFileVersionInfo.GetLanguageIds(Index: Integer): string;
 
- begin
 
-   CheckLanguageIndex(Index);
 
-   Result := VersionLanguageId(FLanguages[Index]);
 
- end;
 
- function TJclFileVersionInfo.GetLanguages(Index: Integer): TLangIdRec;
 
- begin
 
-   CheckLanguageIndex(Index);
 
-   Result := FLanguages[Index];
 
- end;
 
- function TJclFileVersionInfo.GetLanguageNames(Index: Integer): string;
 
- begin
 
-   CheckLanguageIndex(Index);
 
-   Result := VersionLanguageName(FLanguages[Index].LangId);
 
- end;
 
- function TJclFileVersionInfo.GetTranslationCount: Integer;
 
- begin
 
-   Result := Length(FTranslations);
 
- end;
 
- function TJclFileVersionInfo.GetTranslations(Index: Integer): TLangIdRec;
 
- begin
 
-   Result := FTranslations[Index];
 
- end;
 
- function TJclFileVersionInfo.GetProductVersionBuild: string;
 
- var
 
-   Left: Integer;
 
- begin
 
-   Result := ProductVersion;
 
-   StrReplaceChar(Result, ',', '.');
 
-   Left := CharLastPos(Result, '.') + 1;
 
-   Result := StrMid(Result, Left, Length(Result) - Left + 1);
 
-   Result := Trim(Result);
 
- end;
 
- function TJclFileVersionInfo.GetProductVersionMajor: string;
 
- begin
 
-   Result := ProductVersion;
 
-   StrReplaceChar(Result, ',', '.');
 
-   Result := StrBefore('.', Result);
 
-   Result := Trim(Result);
 
- end;
 
- function TJclFileVersionInfo.GetProductVersionMinor: string;
 
- var
 
-   Left, Right: integer;
 
- begin
 
-   Result := ProductVersion;
 
-   StrReplaceChar(Result, ',', '.');
 
-   Left := CharPos(Result, '.') + 1;           // skip major
 
-   Right := CharPos(Result, '.', Left) {-1};
 
-   Result := StrMid(Result, Left, Right - Left {+1});
 
-   Result := Trim(Result);
 
- end;
 
- function TJclFileVersionInfo.GetProductVersionRelease: string;
 
- var
 
-   Left, Right: Integer;
 
- begin
 
-   Result := ProductVersion;
 
-   StrReplaceChar(Result, ',', '.');
 
-   Left := CharPos(Result, '.') + 1;           // skip major
 
-   Left := CharPos(Result, '.', Left) + 1;     // skip minor
 
-   Right := CharPos(Result, '.', Left) {-1};
 
-   Result := StrMid(Result, Left, Right - Left {+1});
 
-   Result := Trim(Result);
 
- end;
 
- function TJclFileVersionInfo.GetVersionKeyValue(Index: Integer): string;
 
- begin
 
-   Result := Items.Values[VerKeyNames[Index]];
 
- end;
 
- procedure TJclFileVersionInfo.SetLanguageIndex(const Value: Integer);
 
- begin
 
-   CheckLanguageIndex(Value);
 
-   if FLanguageIndex <> Value then
 
-   begin
 
-     FLanguageIndex := Value;
 
-     CreateItemsForLanguage;
 
-   end;
 
- end;
 
- function TJclFileVersionInfo.TranslationMatchesLanguages(Exact: Boolean): Boolean;
 
- var
 
-   TransIndex, LangIndex: Integer;
 
-   TranslationPair: DWORD;
 
- begin
 
-   Result := (LanguageCount = TranslationCount) or (not Exact and (TranslationCount > 0));
 
-   if Result then
 
-     for TransIndex := 0 to TranslationCount - 1 do
 
-     begin
 
-       TranslationPair := FTranslations[TransIndex].Pair;
 
-       LangIndex := LanguageCount - 1;
 
-       while (LangIndex >= 0) and (TranslationPair <> FLanguages[LangIndex].Pair) do
 
-         Dec(LangIndex);
 
-       if LangIndex < 0 then
 
-       begin
 
-         Result := False;
 
-         Break;
 
-       end;
 
-     end;
 
- end;
 
- class function TJclFileVersionInfo.VersionLanguageId(const LangIdRec: TLangIdRec): string;
 
- begin
 
-   with LangIdRec do
 
-     Result := Format('%.4x%.4x', [LangId, CodePage]);
 
- end;
 
- class function TJclFileVersionInfo.VersionLanguageName(const LangId: Word): string;
 
- var
 
-   R: DWORD;
 
- begin
 
-   SetLength(Result, MAX_PATH);
 
-   R := VerLanguageName(LangId, PChar(Result), MAX_PATH);
 
-   SetLength(Result, R);
 
- end;
 
- {$ENDIF MSWINDOWS}
 
- //=== { TJclFileMaskComparator } =============================================
 
- constructor TJclFileMaskComparator.Create;
 
- begin
 
-   inherited Create;
 
-   FSeparator := DirSeparator;
 
- end;
 
- function TJclFileMaskComparator.Compare(const NameExt: string): Boolean;
 
- var
 
-   I: Integer;
 
-   NamePart, ExtPart: string;
 
-   NameWild, ExtWild: Boolean;
 
- begin
 
-   Result := False;
 
-   I := StrLastPos('.', NameExt);
 
-   if I = 0 then
 
-   begin
 
-     NamePart := NameExt;
 
-     ExtPart := '';
 
-   end
 
-   else
 
-   begin
 
-     NamePart := Copy(NameExt, 1, I - 1);
 
-     ExtPart := Copy(NameExt, I + 1, Length(NameExt));
 
-   end;
 
-   for I := 0 to Length(FNames) - 1 do
 
-   begin
 
-     NameWild := FWildChars[I] and 1 = 1;
 
-     ExtWild := FWildChars[I] and 2 = 2;
 
-     if ((not NameWild and StrSame(FNames[I], NamePart)) or
 
-       (NameWild and (StrMatches(FNames[I], NamePart, 1)))) and
 
-       ((not ExtWild and StrSame(FExts[I], ExtPart)) or
 
-       (ExtWild and (StrMatches(FExts[I], ExtPart, 1)))) then
 
-     begin
 
-       Result := True;
 
-       Break;
 
-     end;
 
-   end;
 
- end;
 
- procedure TJclFileMaskComparator.CreateMultiMasks;
 
- var
 
-   List: TStringList;
 
-   I, N: Integer;
 
-   NS, ES: string;
 
- begin
 
-   FExts := nil;
 
-   FNames := nil;
 
-   FWildChars := nil;
 
-   List := TStringList.Create;
 
-   try
 
-     StrToStrings(FFileMask, FSeparator, List);
 
-     SetLength(FExts, List.Count);
 
-     SetLength(FNames, List.Count);
 
-     SetLength(FWildChars, List.Count);
 
-     for I := 0 to List.Count - 1 do
 
-     begin
 
-       N := StrLastPos('.', List[I]);
 
-       if N = 0 then
 
-       begin
 
-         NS := List[I];
 
-         ES := '';
 
-       end
 
-       else
 
-       begin
 
-         NS := Copy(List[I], 1, N - 1);
 
-         ES := Copy(List[I], N + 1, 255);
 
-       end;
 
-       FNames[I] := NS;
 
-       FExts[I] := ES;
 
-       N := 0;
 
-       if StrContainsChars(NS, CharIsWildcard, False) then
 
-         N := N or 1;
 
-       if StrContainsChars(ES, CharIsWildcard, False) then
 
-         N := N or 2;
 
-       FWildChars[I] := N;
 
-     end;
 
-   finally
 
-     List.Free;
 
-   end;
 
- end;
 
- function TJclFileMaskComparator.GetCount: Integer;
 
- begin
 
-   Result := Length(FWildChars);
 
- end;
 
- function TJclFileMaskComparator.GetExts(Index: Integer): string;
 
- begin
 
-   Result := FExts[Index];
 
- end;
 
- function TJclFileMaskComparator.GetMasks(Index: Integer): string;
 
- begin
 
-   Result := FNames[Index] + '.' + FExts[Index];
 
- end;
 
- function TJclFileMaskComparator.GetNames(Index: Integer): string;
 
- begin
 
-   Result := FNames[Index];
 
- end;
 
- procedure TJclFileMaskComparator.SetFileMask(const Value: string);
 
- begin
 
-   FFileMask := Value;
 
-   CreateMultiMasks;
 
- end;
 
- procedure TJclFileMaskComparator.SetSeparator(const Value: Char);
 
- begin
 
-   if FSeparator <> Value then
 
-   begin
 
-     FSeparator := Value;
 
-     CreateMultiMasks;
 
-   end;
 
- end;
 
- function AdvBuildFileList(const Path: string; const Attr: Integer; const Files: TStrings;
 
-   const AttributeMatch: TJclAttributeMatch; const Options: TFileListOptions;
 
-   const SubfoldersMask: string; const FileMatchFunc: TFileMatchFunc): Boolean;
 
- var
 
-   FileMask: string;
 
-   RootDir: string;
 
-   Folders: TStringList;
 
-   CurrentItem: Integer;
 
-   Counter: Integer;
 
-   FindAttr: Integer;
 
-   procedure BuildFolderList;
 
-   var
 
-     FindInfo: TSearchRec;
 
-     Rslt: Integer;
 
-   begin
 
-     Counter := Folders.Count - 1;
 
-     CurrentItem := 0;
 
-     while CurrentItem <= Counter do
 
-     begin
 
-       // searching for subfolders (including hidden ones)
 
-       Rslt := FindFirst(Folders[CurrentItem] + '*.*', faAnyFile, FindInfo);
 
-       try
 
-         while Rslt = 0 do
 
-         begin
 
-           if (FindInfo.Name <> '.') and (FindInfo.Name <> '..') and
 
-             (FindInfo.Attr and faDirectory = faDirectory) then
 
-             Folders.Add(Folders[CurrentItem] + FindInfo.Name + DirDelimiter);
 
-           Rslt := FindNext(FindInfo);
 
-         end;
 
-       finally
 
-         FindClose(FindInfo);
 
-       end;
 
-       Counter := Folders.Count - 1;
 
-       Inc(CurrentItem);
 
-     end;
 
-   end;
 
-   procedure FillFileList(CurrentCounter: Integer);
 
-   var
 
-     FindInfo: TSearchRec;
 
-     Rslt: Integer;
 
-     CurrentFolder: string;
 
-     Matches: Boolean;
 
-   begin
 
-     CurrentFolder := Folders[CurrentCounter];
 
-     Rslt := FindFirst(CurrentFolder + FileMask, FindAttr, FindInfo);
 
-     try
 
-       while Rslt = 0 do
 
-       begin
 
-          Matches := False;
 
-          case AttributeMatch of
 
-            amAny:
 
-              Matches := True;
 
-            amExact:
 
-              Matches := Attr = FindInfo.Attr;
 
-            amSubSetOf:
 
-              Matches := (Attr and FindInfo.Attr) = Attr;
 
-            amSuperSetOf:
 
-              Matches := (Attr and FindInfo.Attr) = FindInfo.Attr;
 
-            amCustom:
 
-              if Assigned(FileMatchFunc) then
 
-                Matches := FileMatchFunc(Attr,  FindInfo);
 
-          end;
 
-          if Matches then
 
-            if flFullNames in Options then
 
-              Files.Add(CurrentFolder + FindInfo.Name)
 
-            else
 
-              Files.Add(FindInfo.Name);
 
-         Rslt := FindNext(FindInfo);
 
-       end;
 
-     finally
 
-       FindClose(FindInfo);
 
-     end;
 
-   end;
 
- begin
 
-   Assert(Assigned(Files));
 
-   FileMask := ExtractFileName(Path);
 
-   RootDir := ExtractFilePath(Path);
 
-   Folders := TStringList.Create;
 
-   Files.BeginUpdate;
 
-   try
 
-     Folders.Add(RootDir);
 
-     case AttributeMatch of
 
-       amExact, amSuperSetOf:
 
-         FindAttr := Attr;
 
-     else
 
-       FindAttr := faAnyFile;
 
-     end;
 
-     // here's the recursive search for nested folders
 
-     if flRecursive in Options then
 
-       BuildFolderList;
 
-     for Counter := 0 to Folders.Count - 1 do
 
-     begin
 
-       if (((flMaskedSubfolders in Options) and (StrMatches(SubfoldersMask,
 
-         Folders[Counter], 1))) or (not (flMaskedSubfolders in Options))) then
 
-           FillFileList(Counter);
 
-     end;
 
-   finally
 
-     Folders.Free;
 
-     Files.EndUpdate;
 
-   end;
 
-   Result := True;
 
- end;
 
- function VerifyFileAttributeMask(var RejectedAttributes, RequiredAttributes: Integer): Boolean;
 
- begin
 
-   if RequiredAttributes and faNormalFile <> 0 then
 
-     RejectedAttributes := not faNormalFile or RejectedAttributes;
 
-   Result := RequiredAttributes and RejectedAttributes = 0;
 
- end;
 
- function AttributeMatch(FileAttributes, RejectedAttr, RequiredAttr: Integer): Boolean;
 
- begin
 
-   if FileAttributes = 0 then
 
-     FileAttributes := faNormalFile;
 
-   {$IFDEF MSWINDOWS}
 
-   RequiredAttr := RequiredAttr and not faUnixSpecific;
 
-   {$ENDIF MSWINDOWS}
 
-   {$IFDEF UNIX}
 
-   RequiredAttr := RequiredAttr and not faWindowsSpecific;
 
-   {$ENDIF UNIX}
 
-   Result := (FileAttributes and RejectedAttr = 0)
 
-     and (FileAttributes and RequiredAttr = RequiredAttr);
 
- end;
 
- function IsFileAttributeMatch(FileAttributes, RejectedAttributes,
 
-   RequiredAttributes: Integer): Boolean;
 
- begin
 
-   VerifyFileAttributeMask(RejectedAttributes, RequiredAttributes);
 
-   Result := AttributeMatch(FileAttributes, RejectedAttributes, RequiredAttributes);
 
- end;
 
- function FileAttributesStr(const FileInfo: TSearchRec): string;
 
- {$IFDEF MSWINDOWS}
 
- const
 
-   SAllAttrSet = 'rahs'; // readonly, archive, hidden, system
 
-   Attributes: array [1..4] of Integer =
 
-     (faReadOnly, faArchive, faHidden, faSysFile);
 
- var
 
-   I: Integer;
 
- begin
 
-   Result := SAllAttrSet;
 
-   for I := Low(Attributes) to High(Attributes) do
 
-     if (FileInfo.Attr and Attributes[I]) = 0 then
 
-       Result[I] := '-';
 
- end;
 
- {$ENDIF MSWINDOWS}
 
- {$IFDEF UNIX}
 
- const
 
-   SAllAttrSet = 'drwxrwxrwx';
 
- var
 
-   I: Integer;
 
-   Flag: Cardinal;
 
- begin
 
-   Result := SAllAttrSet;
 
-   if FileInfo.Attr and faDirectory = 0 then
 
-     Result[1] := '-'; // no directory
 
-   Flag := 1 shl 8;
 
-   for I := 2 to 10 do
 
-   begin
 
-     if FileInfo.Mode and Flag = 0 then
 
-       Result[I] := '-';
 
-     Flag := Flag shr 1;
 
-   end;
 
- end;
 
- {$ENDIF UNIX}
 
- function IsFileNameMatch(FileName: string; const Mask: string;
 
-   const CaseSensitive: Boolean): Boolean;
 
- begin
 
-   Result := True;
 
-   {$IFDEF MSWINDOWS}
 
-   if (Mask = '') or (Mask = '*') or (Mask = '*.*') then
 
-     Exit;
 
-   if Pos('.', FileName) = 0 then
 
-     FileName := FileName + '.';  // file names w/o extension match '*.'
 
-   {$ENDIF MSWINDOWS}
 
-   {$IFDEF UNIX}
 
-   if (Mask = '') or (Mask = '*') then
 
-     Exit;
 
-   {$ENDIF UNIX}
 
-   if CaseSensitive then
 
-     Result := StrMatches(Mask, FileName)
 
-   else
 
-     Result := StrMatches(AnsiUpperCase(Mask), AnsiUpperCase(FileName));
 
- end;
 
- // author: Robert Rossmair
 
- function CanonicalizedSearchPath(const Directory: string): string;
 
- begin
 
-   Result := PathCanonicalize(Directory);
 
-   {$IFDEF MSWINDOWS}
 
-   // avoid changing "X:" (current directory on drive X:) into "X:\" (root dir.)
 
-   if Result[Length(Result)] <> ':' then
 
-   {$ENDIF MSWINDOWS}
 
-     Result := PathAddSeparator(Result);
 
-   // strip leading "./" resp. ".\"
 
-   if Pos('.' + DirDelimiter, Result) = 1 then
 
-     Result := Copy(Result, 3, Length(Result) - 2);
 
- end;
 
- procedure EnumFiles(const Path: string; HandleFile: TFileHandlerEx;
 
-   RejectedAttributes: Integer; RequiredAttributes: Integer; Abort: PBoolean);
 
- var
 
-   Directory: string;
 
-   FileInfo: TSearchRec;
 
-   Attr: Integer;
 
-   Found: Boolean;
 
- begin
 
-   Assert(Assigned(HandleFile));
 
-   Assert(VerifyFileAttributeMask(RejectedAttributes, RequiredAttributes),
 
-     LoadResString(@RsFileSearchAttrInconsistency));
 
-   Directory := ExtractFilePath(Path);
 
-   Attr := faAnyFile and not RejectedAttributes;
 
-   Found := {$IFDEF HAS_UNITSCOPE}System.{$ENDIF}SysUtils.FindFirst(Path, Attr, FileInfo) = 0;
 
-   try
 
-     while Found do
 
-     begin
 
-       if (Abort <> nil) and LongBool(Abort^) then
 
-         Exit;
 
-       if AttributeMatch(FileInfo.Attr, RejectedAttributes, RequiredAttributes) then
 
-         if ((FileInfo.Attr and faDirectory = 0)
 
-         or ((FileInfo.Name <> '.') and (FileInfo.Name <> '..'))) then
 
-           HandleFile(Directory, FileInfo);
 
-       Found := FindNext(FileInfo) = 0;
 
-     end;
 
-   finally
 
-     FindClose(FileInfo);
 
-   end;
 
- end;
 
- procedure EnumFiles(const Path: string; HandleFile: TFileInfoHandlerEx;
 
-   RejectedAttributes: Integer; RequiredAttributes: Integer; Abort: PBoolean);
 
- var
 
-   FileInfo: TSearchRec;
 
-   Attr: Integer;
 
-   Found: Boolean;
 
- begin
 
-   Assert(Assigned(HandleFile));
 
-   Assert(VerifyFileAttributeMask(RejectedAttributes, RequiredAttributes),
 
-     LoadResString(@RsFileSearchAttrInconsistency));
 
-   Attr := faAnyFile and not RejectedAttributes;
 
-   Found := {$IFDEF HAS_UNITSCOPE}System.{$ENDIF}SysUtils.FindFirst(Path, Attr, FileInfo) = 0;
 
-   try
 
-     while Found do
 
-     begin
 
-       if (Abort <> nil) and LongBool(Abort^) then
 
-         Exit;
 
-       if AttributeMatch(FileInfo.Attr, RejectedAttributes, RequiredAttributes) then
 
-         if ((FileInfo.Attr and faDirectory = 0)
 
-         or ((FileInfo.Name <> '.') and (FileInfo.Name <> '..'))) then
 
-           HandleFile(FileInfo);
 
-       Found := FindNext(FileInfo) = 0;
 
-     end;
 
-   finally
 
-     FindClose(FileInfo);
 
-   end;
 
- end;
 
- procedure EnumDirectories(const Root: string; const HandleDirectory: TFileHandler;
 
-   const IncludeHiddenDirectories: Boolean; const SubDirectoriesMask: string;
 
-   Abort: PBoolean {$IFDEF UNIX}; ResolveSymLinks: Boolean {$ENDIF});
 
- var
 
-   RootDir: string;
 
-   Attr: Integer;
 
-   procedure Process(const Directory: string);
 
-   var
 
-     DirInfo: TSearchRec;
 
-     SubDir: string;
 
-     Found: Boolean;
 
-   begin
 
-     HandleDirectory(Directory);
 
-     Found := {$IFDEF HAS_UNITSCOPE}System.{$ENDIF}SysUtils.FindFirst(Directory + '*', Attr, DirInfo) = 0;
 
-     try
 
-       while Found do
 
-       begin
 
-         if (Abort <> nil) and LongBool(Abort^) then
 
-           Exit;
 
-         if (DirInfo.Name <> '.') and (DirInfo.Name <> '..') and
 
-           {$IFDEF UNIX}
 
-           (IncludeHiddenDirectories or (Pos('.', DirInfo.Name) <> 1)) and
 
-           ((DirInfo.Attr and faSymLink = 0) or ResolveSymLinks) and
 
-           {$ENDIF UNIX}
 
-           (DirInfo.Attr and faDirectory <> 0) then
 
-         begin
 
-           SubDir := Directory + DirInfo.Name + DirDelimiter;
 
-           if (SubDirectoriesMask = '') or StrMatches(SubDirectoriesMask, SubDir, Length(RootDir)) then
 
-             Process(SubDir);
 
-         end;
 
-         Found := FindNext(DirInfo) = 0;
 
-       end;
 
-     finally
 
-       FindClose(DirInfo);
 
-     end;
 
-   end;
 
- begin
 
-   Assert(Assigned(HandleDirectory));
 
-   RootDir := CanonicalizedSearchPath(Root);
 
-   if IncludeHiddenDirectories then
 
-     Attr := faDirectory + faHidden  // no effect on Linux
 
-   else
 
-     Attr := faDirectory;
 
-   Process(RootDir);
 
- end;
 
- //=== { TJclCustomFileAttributeMask } ==============================================
 
- constructor TJclCustomFileAttrMask.Create;
 
- begin
 
-   inherited Create;
 
-   FRejectedAttr := faRejectedByDefault;
 
- end;
 
- procedure TJclCustomFileAttrMask.Assign(Source: TPersistent);
 
- begin
 
-   if Source is TJclCustomFileAttrMask then
 
-   begin
 
-     Required := TJclCustomFileAttrMask(Source).Required;
 
-     Rejected := TJclCustomFileAttrMask(Source).Rejected;
 
-   end
 
-   else
 
-     inherited Assign(Source);
 
- end;
 
- procedure TJclCustomFileAttrMask.Clear;
 
- begin
 
-   Rejected := 0;
 
-   Required := 0;
 
- end;
 
- procedure TJclCustomFileAttrMask.DefineProperties(Filer: TFiler);
 
- var
 
-   Ancestor: TJclCustomFileAttrMask;
 
-   Attr: Integer;
 
- begin
 
-   Attr := 0;
 
-   Ancestor := TJclCustomFileAttrMask(Filer.Ancestor);
 
-   if Assigned(Ancestor) then
 
-     Attr := Ancestor.FRequiredAttr;
 
-   Filer.DefineProperty('Required', ReadRequiredAttributes, WriteRequiredAttributes,
 
-     Attr <> FRequiredAttr);
 
-   if Assigned(Ancestor) then
 
-     Attr := Ancestor.FRejectedAttr;
 
-   Filer.DefineProperty('Rejected', ReadRejectedAttributes, WriteRejectedAttributes,
 
-     Attr <> FRejectedAttr);
 
- end;
 
- function TJclCustomFileAttrMask.Match(FileAttributes: Integer): Boolean;
 
- begin
 
-   Result := AttributeMatch(FileAttributes, Rejected, Required);
 
- end;
 
- function TJclCustomFileAttrMask.Match(const FileInfo: TSearchRec): Boolean;
 
- begin
 
-   Result := Match(FileInfo.Attr);
 
- end;
 
- function TJclCustomFileAttrMask.GetAttr(Index: Integer): TAttributeInterest;
 
- begin
 
-   if ((FRequiredAttr and Index) <> 0) or (Index = faNormalFile) and
 
-     (FRejectedAttr = not faNormalFile) then
 
-     Result := aiRequired
 
-   else
 
-   if (FRejectedAttr and Index) <> 0 then
 
-     Result := aiRejected
 
-   else
 
-     Result := aiIgnored;
 
- end;
 
- procedure TJclCustomFileAttrMask.ReadRejectedAttributes(Reader: TReader);
 
- begin
 
-   FRejectedAttr := Reader.ReadInteger;
 
- end;
 
- procedure TJclCustomFileAttrMask.ReadRequiredAttributes(Reader: TReader);
 
- begin
 
-   FRequiredAttr := Reader.ReadInteger;
 
- end;
 
- procedure TJclCustomFileAttrMask.SetAttr(Index: Integer; const Value: TAttributeInterest);
 
- begin
 
-   case Value of
 
-     aiIgnored:
 
-       begin
 
-         FRequiredAttr := FRequiredAttr and not Index;
 
-         FRejectedAttr := FRejectedAttr and not Index;
 
-       end;
 
-     aiRejected:
 
-       begin
 
-         FRequiredAttr := FRequiredAttr and not Index;
 
-         FRejectedAttr := FRejectedAttr or Index;
 
-       end;
 
-     aiRequired:
 
-       begin
 
-         if Index = faNormalFile then
 
-         begin
 
-           FRequiredAttr := faNormalFile;
 
-           FRejectedAttr := not faNormalFile;
 
-         end
 
-         else
 
-         begin
 
-           FRequiredAttr := FRequiredAttr or Index;
 
-           FRejectedAttr := FRejectedAttr and not Index;
 
-         end;
 
-       end;
 
-   end;
 
- end;
 
- procedure TJclCustomFileAttrMask.WriteRejectedAttributes(Writer: TWriter);
 
- begin
 
-   Writer.WriteInteger(FRejectedAttr);
 
- end;
 
- procedure TJclCustomFileAttrMask.WriteRequiredAttributes(Writer: TWriter);
 
- begin
 
-   Writer.WriteInteger(FRequiredAttr);
 
- end;
 
- //=== { TJclFileAttributeMask } ==============================================
 
- procedure TJclFileAttributeMask.ReadVolumeID(Reader: TReader);
 
- begin
 
-   // Nothing, we are not interested in the value of the VolumeID property,
 
-   // this procedure and the associated DefineProperty call are here only
 
-   // to allow reading legacy DFMs that have this property defined.
 
- end;
 
- procedure TJclFileAttributeMask.DefineProperties(Filer: TFiler);
 
- begin
 
-   inherited DefineProperties(Filer);
 
-   Filer.DefineProperty('VolumeID', ReadVolumeID, nil, False);
 
- end;
 
- //=== { TJclFileSearchOptions } ==============================================
 
- constructor TJclFileSearchOptions.Create;
 
- begin
 
-   inherited Create;
 
-   FAttributeMask := TJclFileAttributeMask.Create;
 
-   FRootDirectories := TStringList.Create;
 
-   FRootDirectories.Add('.');
 
-   FFileMasks := TStringList.Create;
 
-   FFileMasks.Add('*');
 
-   FSubDirectoryMask := '*';
 
-   FOptions := [fsIncludeSubDirectories];
 
-   FLastChangeAfter := MinDateTime;
 
-   FLastChangeBefore := MaxDateTime;
 
-   {$IFDEF UNIX}
 
-   FCaseSensitiveSearch := True;
 
-   {$ENDIF UNIX}
 
- end;
 
- destructor TJclFileSearchOptions.Destroy;
 
- begin
 
-   FAttributeMask.Free;
 
-   FFileMasks.Free;
 
-   FRootDirectories.Free;
 
-   inherited Destroy;
 
- end;
 
- procedure TJclFileSearchOptions.Assign(Source: TPersistent);
 
- var
 
-   Src: TJclFileSearchOptions;
 
- begin
 
-   if Source is TJclFileSearchOptions then
 
-   begin
 
-     Src := TJclFileSearchOptions(Source);
 
-     FCaseSensitiveSearch := Src.FCaseSensitiveSearch;
 
-     FileMasks.Assign(Src.FileMasks);
 
-     RootDirectory := Src.RootDirectory;
 
-     SubDirectoryMask := Src.SubDirectoryMask;
 
-     AttributeMask := Src.AttributeMask;
 
-     Options := Src.Options;
 
-     FileSizeMin := Src.FileSizeMin;
 
-     FileSizeMax := Src.FileSizeMax;
 
-     LastChangeAfter := Src.LastChangeAfter;
 
-     LastChangeBefore := Src.LastChangeBefore;
 
-   end
 
-   else
 
-     inherited Assign(Source);
 
- end;
 
- function TJclFileSearchOptions.GetAttributeMask: TJclFileAttributeMask;
 
- begin
 
-   Result := FAttributeMask;
 
- end;
 
- function TJclFileSearchOptions.GetCaseSensitiveSearch: Boolean;
 
- begin
 
-   Result := FCaseSensitiveSearch;
 
- end;
 
- function TJclFileSearchOptions.GetFileMask: string;
 
- begin
 
-   Result := StringsToStr(FileMasks, DirSeparator, False);
 
- end;
 
- function TJclFileSearchOptions.GetFileMasks: TStrings;
 
- begin
 
-   Result := FFileMasks;
 
- end;
 
- function TJclFileSearchOptions.GetFileSizeMax: Int64;
 
- begin
 
-   Result := FFileSizeMax;
 
- end;
 
- function TJclFileSearchOptions.GetFileSizeMin: Int64;
 
- begin
 
-   Result := FFileSizeMin;
 
- end;
 
- function TJclFileSearchOptions.GetIncludeHiddenSubDirectories: Boolean;
 
- begin
 
-   Result := fsIncludeHiddenSubDirectories in Options;
 
- end;
 
- function TJclFileSearchOptions.GetIncludeSubDirectories: Boolean;
 
- begin
 
-   Result := fsIncludeSubDirectories in Options;
 
- end;
 
- function TJclFileSearchOptions.GetLastChangeAfter: TDateTime;
 
- begin
 
-   Result := FLastChangeAfter;
 
- end;
 
- function TJclFileSearchOptions.GetLastChangeAfterStr: string;
 
- begin
 
-   Result := DateTimeToStr(LastChangeAfter);
 
- end;
 
- function TJclFileSearchOptions.GetLastChangeBefore: TDateTime;
 
- begin
 
-   Result := FLastChangeBefore;
 
- end;
 
- function TJclFileSearchOptions.GetLastChangeBeforeStr: string;
 
- begin
 
-   Result := DateTimeToStr(LastChangeBefore);
 
- end;
 
- function TJclFileSearchOptions.GetOption(
 
-   const Option: TFileSearchOption): Boolean;
 
- begin
 
-   Result := Option in FOptions;
 
- end;
 
- function TJclFileSearchOptions.GetOptions: TFileSearchoptions;
 
- begin
 
-   Result := FOptions;
 
- end;
 
- function TJclFileSearchOptions.GetRootDirectories: TStrings;
 
- begin
 
-   Result := FRootDirectories;
 
- end;
 
- function TJclFileSearchOptions.GetRootDirectory: string;
 
- begin
 
-   if FRootDirectories.Count = 1 then
 
-     Result := FRootDirectories.Strings[0]
 
-   else
 
-     Result := '';
 
- end;
 
- function TJclFileSearchOptions.GetSubDirectoryMask: string;
 
- begin
 
-   Result := FSubDirectoryMask;
 
- end;
 
- function TJclFileSearchOptions.IsLastChangeAfterStored: Boolean;
 
- begin
 
-   Result := FLastChangeAfter <> MinDateTime;
 
- end;
 
- function TJclFileSearchOptions.IsLastChangeBeforeStored: Boolean;
 
- begin
 
-   Result := FLastChangeBefore <> MaxDateTime;
 
- end;
 
- procedure TJclFileSearchOptions.SetAttributeMask(
 
-   const Value: TJclFileAttributeMask);
 
- begin
 
-   FAttributeMask.Assign(Value);
 
- end;
 
- procedure TJclFileSearchOptions.SetCaseSensitiveSearch(const Value: Boolean);
 
- begin
 
-   FCaseSensitiveSearch := Value;
 
- end;
 
- procedure TJclFileSearchOptions.SetFileMask(const Value: string);
 
- begin
 
-   { TODO : UNIX : ? }
 
-   StrToStrings(Value, DirSeparator, FFileMasks, False);
 
- end;
 
- procedure TJclFileSearchOptions.SetFileMasks(const Value: TStrings);
 
- begin
 
-   FileMasks.Assign(Value);
 
- end;
 
- procedure TJclFileSearchOptions.SetFileSizeMax(const Value: Int64);
 
- begin
 
-   FFileSizeMax := Value;
 
- end;
 
- procedure TJclFileSearchOptions.SetFileSizeMin(const Value: Int64);
 
- begin
 
-   FFileSizeMin := Value;
 
- end;
 
- procedure TJclFileSearchOptions.SetIncludeHiddenSubDirectories(
 
-   const Value: Boolean);
 
- begin
 
-   SetOption(fsIncludeHiddenSubDirectories, Value);
 
- end;
 
- procedure TJclFileSearchOptions.SetIncludeSubDirectories(const Value: Boolean);
 
- begin
 
-   SetOption(fsIncludeSubDirectories, Value);
 
- end;
 
- procedure TJclFileSearchOptions.SetLastChangeAfter(const Value: TDateTime);
 
- begin
 
-   FLastChangeAfter := Value;
 
- end;
 
- procedure TJclFileSearchOptions.SetLastChangeAfterStr(const Value: string);
 
- begin
 
-   if Value = '' then
 
-     LastChangeAfter := MinDateTime
 
-   else
 
-     LastChangeAfter := StrToDateTime(Value);
 
- end;
 
- procedure TJclFileSearchOptions.SetLastChangeBefore(const Value: TDateTime);
 
- begin
 
-   FLastChangeBefore := Value;
 
- end;
 
- procedure TJclFileSearchOptions.SetLastChangeBeforeStr(const Value: string);
 
- begin
 
-   if Value = '' then
 
-     LastChangeBefore := MaxDateTime
 
-   else
 
-     LastChangeBefore := StrToDateTime(Value);
 
- end;
 
- procedure TJclFileSearchOptions.SetOption(const Option: TFileSearchOption;
 
-   const Value: Boolean);
 
- begin
 
-   if Value then
 
-     Include(FOptions, Option)
 
-   else
 
-     Exclude(FOptions, Option);
 
- end;
 
- procedure TJclFileSearchOptions.SetOptions(const Value: TFileSearchOptions);
 
- begin
 
-   FOptions := Value;
 
- end;
 
- procedure TJclFileSearchOptions.SetRootDirectories(const Value: TStrings);
 
- begin
 
-   FRootDirectories.Assign(Value);
 
- end;
 
- procedure TJclFileSearchOptions.SetRootDirectory(const Value: string);
 
- begin
 
-   FRootDirectories.Clear;
 
-   FRootDirectories.Add(Value);
 
- end;
 
- procedure TJclFileSearchOptions.SetSubDirectoryMask(const Value: string);
 
- begin
 
-   FSubDirectoryMask := Value;
 
- end;
 
- //=== { TEnumFileThread } ====================================================
 
- type
 
-   TEnumFileThread = class(TThread)
 
-   private
 
-     FID: TFileSearchTaskID;
 
-     FFileMasks: TStringList;
 
-     FDirectories: TStrings;
 
-     FCurrentDirectory: string;
 
-     FSubDirectoryMask: string;
 
-     FOnEnterDirectory: TFileHandler;
 
-     FFileHandlerEx: TFileHandlerEx;
 
-     FFileHandler: TFileHandler;
 
-     FInternalDirHandler: TFileHandler;
 
-     FInternalFileInfoHandler: TFileInfoHandlerEx;
 
-     FFileInfo: TSearchRec;
 
-     FRejectedAttr: Integer;
 
-     FRequiredAttr: Integer;
 
-     FFileSizeMin: Int64;
 
-     FFileSizeMax: Int64;
 
-     {$IFDEF RTL220_UP}
 
-     FFileTimeMin: TDateTime;
 
-     FFileTimeMax: TDateTime;
 
-     {$ELSE ~RTL220_UP}
 
-     FFileTimeMin: Integer;
 
-     FFileTimeMax: Integer;
 
-     {$ENDIF ~RTL220_UP}
 
-     FSynchronizationMode: TFileEnumeratorSyncMode;
 
-     FIncludeSubDirectories: Boolean;
 
-     FIncludeHiddenSubDirectories: Boolean;
 
-     FNotifyOnTermination: Boolean;
 
-     FCaseSensitiveSearch: Boolean;
 
-     FAllNamesMatch: Boolean;
 
-     procedure EnterDirectory;
 
-     procedure AsyncProcessDirectory(const Directory: string);
 
-     procedure SyncProcessDirectory(const Directory: string);
 
-     procedure AsyncProcessFile(const FileInfo: TSearchRec);
 
-     procedure SyncProcessFile(const FileInfo: TSearchRec);
 
-     function GetDirectories: TStrings;
 
-     function GetFileMasks: TStrings;
 
-     procedure SetDirectories(const Value: TStrings);
 
-     procedure SetFileMasks(const Value: TStrings);
 
-   protected
 
-     procedure DoTerminate; override;
 
-     procedure Execute; override;
 
-     function FileMatch: Boolean;
 
-     function FileNameMatchesMask: Boolean;
 
-     procedure ProcessDirectory;
 
-     procedure ProcessDirFiles;
 
-     procedure ProcessFile;
 
-     property AllNamesMatch: Boolean read FAllNamesMatch;
 
-     property CaseSensitiveSearch: Boolean read FCaseSensitiveSearch write FCaseSensitiveSearch;
 
-     property FileMasks: TStrings read GetFileMasks write SetFileMasks;
 
-     property FileSizeMin: Int64 read FFileSizeMin write FFileSizeMin;
 
-     property FileSizeMax: Int64 read FFileSizeMax write FFileSizeMax;
 
-     {$IFDEF RTL220_UP}
 
-     property FileTimeMin: TDateTime read FFileTimeMin write FFileTimeMin;
 
-     property FileTimeMax: TDateTime read FFileTimeMax write FFileTimeMax;
 
-     {$ELSE ~RTL220_UP}
 
-     property FileTimeMin: Integer read FFileTimeMin write FFileTimeMin;
 
-     property FileTimeMax: Integer read FFileTimeMax write FFileTimeMax;
 
-     {$ENDIF ~RTL220_UP}
 
-     property Directories: TStrings read GetDirectories write SetDirectories;
 
-     property IncludeSubDirectories: Boolean
 
-       read FIncludeSubDirectories write FIncludeSubDirectories;
 
-     property IncludeHiddenSubDirectories: Boolean
 
-       read FIncludeHiddenSubDirectories write FIncludeHiddenSubDirectories;
 
-     property RejectedAttr: Integer read FRejectedAttr write FRejectedAttr;
 
-     property RequiredAttr: Integer read FRequiredAttr write FRequiredAttr;
 
-     property SynchronizationMode: TFileEnumeratorSyncMode
 
-       read FSynchronizationMode write FSynchronizationMode;
 
-   public
 
-     constructor Create;
 
-     destructor Destroy; override;
 
-     property ID: TFileSearchTaskID read FID;
 
-     {$IFDEF FPC} // protected property
 
-     property Terminated;
 
-     {$ENDIF FPC}
 
-   end;
 
- constructor TEnumFileThread.Create;
 
- begin
 
-   inherited Create(True);
 
-   FDirectories := TStringList.Create;
 
-   FFileMasks := TStringList.Create;
 
-   {$IFDEF RTL220_UP}
 
-   FFileTimeMin := -MaxDouble;
 
-   FFileTimeMax := MaxDouble;
 
-   {$ELSE ~RTL220_UP}
 
-   FFileTimeMin := Low(FFileInfo.Time);
 
-   FFileTimeMax := High(FFileInfo.Time);
 
-   {$ENDIF ~RTL220_UP}
 
-   FFileSizeMax := High(FFileSizeMax);
 
-   {$IFDEF MSWINDOWS}
 
-   Priority := tpIdle;
 
-   {$ENDIF MSWINDOWS}
 
-   {$IFDEF UNIX}
 
-   {$IFDEF FPC}
 
-   Priority := tpIdle;
 
-   {$ELSE ~FPC}
 
-   Priority := 0;
 
-   {$ENDIF ~FPC}
 
-   {$ENDIF UNIX}
 
-   FreeOnTerminate := True;
 
-   FNotifyOnTermination := True;
 
- end;
 
- destructor TEnumFileThread.Destroy;
 
- begin
 
-   FFileMasks.Free;
 
-   FDirectories.Free;
 
-   inherited Destroy;
 
- end;
 
- procedure TEnumFileThread.Execute;
 
- var
 
-   Index: Integer;
 
- begin
 
-   if SynchronizationMode = smPerDirectory then
 
-   begin
 
-     FInternalDirHandler := SyncProcessDirectory;
 
-     FInternalFileInfoHandler := AsyncProcessFile;
 
-   end
 
-   else // SynchronizationMode = smPerFile
 
-   begin
 
-     FInternalDirHandler := AsyncProcessDirectory;
 
-     FInternalFileInfoHandler := SyncProcessFile;
 
-   end;
 
-   if FIncludeSubDirectories then
 
-   begin
 
-     for Index := 0 to FDirectories.Count - 1 do
 
-       EnumDirectories(FDirectories.Strings[Index], FInternalDirHandler, FIncludeHiddenSubDirectories,
 
-         FSubDirectoryMask, @Terminated)
 
-   end
 
-   else
 
-   begin
 
-     for Index := 0 to FDirectories.Count - 1 do
 
-       FInternalDirHandler(CanonicalizedSearchPath(FDirectories.Strings[Index]));
 
-   end;
 
- end;
 
- procedure TEnumFileThread.DoTerminate;
 
- begin
 
-   if FNotifyOnTermination then
 
-     inherited DoTerminate;
 
- end;
 
- procedure TEnumFileThread.EnterDirectory;
 
- begin
 
-   FOnEnterDirectory(FCurrentDirectory);
 
- end;
 
- procedure TEnumFileThread.ProcessDirectory;
 
- begin
 
-   if Assigned(FOnEnterDirectory) then
 
-     EnterDirectory;
 
-   ProcessDirFiles;
 
- end;
 
- procedure TEnumFileThread.AsyncProcessDirectory(const Directory: string);
 
- begin
 
-   FCurrentDirectory := Directory;
 
-   if Assigned(FOnEnterDirectory) then
 
-     Synchronize(EnterDirectory);
 
-   ProcessDirFiles;
 
- end;
 
- procedure TEnumFileThread.SyncProcessDirectory(const Directory: string);
 
- begin
 
-   FCurrentDirectory := Directory;
 
-   Synchronize(ProcessDirectory);
 
- end;
 
- procedure TEnumFileThread.ProcessDirFiles;
 
- begin
 
-   EnumFiles(FCurrentDirectory + '*', FInternalFileInfoHandler, FRejectedAttr, FRequiredAttr, @Terminated);
 
- end;
 
- function TEnumFileThread.FileMatch: Boolean;
 
- var
 
-   FileSize: Int64;
 
- begin
 
-   {$IFDEF RTL220_UP}
 
-   Result := FileNameMatchesMask and (FFileInfo.TimeStamp >= FFileTimeMin) and (FFileInfo.TimeStamp <= FFileTimeMax);
 
-   {$ELSE ~RTL220_UP}
 
-   Result := FileNameMatchesMask and (FFileInfo.Time >= FFileTimeMin) and (FFileInfo.Time <= FFileTimeMax);
 
-   {$ENDIF ~RTL220_UP}
 
-   if Result then
 
-   begin
 
-     FileSize := GetSizeOfFile(FFileInfo);
 
-     Result := (FileSize >= FFileSizeMin) and (FileSize <= FFileSizeMax);
 
-   end;
 
- end;
 
- function TEnumFileThread.FileNameMatchesMask: Boolean;
 
- var
 
-   I: Integer;
 
- begin
 
-   Result := AllNamesMatch;
 
-   if not Result then
 
-     for I := 0 to FileMasks.Count - 1 do
 
-       if IsFileNameMatch(FFileInfo.Name, FileMasks[I], CaseSensitiveSearch) then
 
-       begin
 
-         Result := True;
 
-         Break;
 
-       end;
 
- end;
 
- procedure TEnumFileThread.ProcessFile;
 
- begin
 
-   if Assigned(FFileHandlerEx) then
 
-     FFileHandlerEx(FCurrentDirectory, FFileInfo)
 
-   else
 
-     FFileHandler(FCurrentDirectory + FFileInfo.Name);
 
- end;
 
- procedure TEnumFileThread.AsyncProcessFile(const FileInfo: TSearchRec);
 
- begin
 
-   FFileInfo := FileInfo;
 
-   if FileMatch then
 
-     ProcessFile;
 
- end;
 
- procedure TEnumFileThread.SyncProcessFile(const FileInfo: TSearchRec);
 
- begin
 
-   FFileInfo := FileInfo;
 
-   if FileMatch then
 
-     Synchronize(ProcessFile);
 
- end;
 
- function TEnumFileThread.GetDirectories: TStrings;
 
- begin
 
-   Result := FDirectories;
 
- end;
 
- function TEnumFileThread.GetFileMasks: TStrings;
 
- begin
 
-   Result := FFileMasks;
 
- end;
 
- procedure TEnumFileThread.SetDirectories(const Value: TStrings);
 
- begin
 
-   FDirectories.Assign(Value);
 
- end;
 
- procedure TEnumFileThread.SetFileMasks(const Value: TStrings);
 
- var
 
-   I: Integer;
 
- begin
 
-   FAllNamesMatch := Value.Count = 0;
 
-   for I := 0 to Value.Count - 1 do
 
-     if (Value[I] = '*') {$IFDEF MSWINDOWS} or (Value[I] = '*.*') {$ENDIF} then
 
-     begin
 
-       FAllNamesMatch := True;
 
-       Break;
 
-     end;
 
-   if FAllNamesMatch then
 
-     FileMasks.Clear
 
-   else
 
-     FileMasks.Assign(Value);
 
- end;
 
- //=== { TJclFileEnumerator } =================================================
 
- constructor TJclFileEnumerator.Create;
 
- begin
 
-   inherited Create;
 
-   FTasks := TList.Create;
 
- end;
 
- destructor TJclFileEnumerator.Destroy;
 
- begin
 
-   StopAllTasks(True);
 
-   FTasks.Free;
 
-   inherited Destroy;
 
- end;
 
- procedure TJclFileEnumerator.Assign(Source: TPersistent);
 
- var
 
-   Src: TJclFileEnumerator;
 
- begin
 
-   if Source is TJclFileEnumerator then
 
-   begin
 
-     Src := TJclFileEnumerator(Source);
 
-     SynchronizationMode := Src.SynchronizationMode;
 
-     OnEnterDirectory := Src.OnEnterDirectory;
 
-     OnTerminateTask := Src.OnTerminateTask;
 
-   end;
 
-   inherited Assign(Source);
 
- end;
 
- function TJclFileEnumerator.CreateTask: TThread;
 
- var
 
-   Task: TEnumFileThread;
 
- begin
 
-   Task := TEnumFileThread.Create;
 
-   Task.FID := NextTaskID;
 
-   Task.CaseSensitiveSearch := FCaseSensitiveSearch;
 
-   Task.FileMasks := FileMasks;
 
-   Task.Directories := RootDirectories;
 
-   Task.RejectedAttr := AttributeMask.Rejected;
 
-   Task.RequiredAttr := AttributeMask.Required;
 
-   Task.IncludeSubDirectories := IncludeSubDirectories;
 
-   Task.IncludeHiddenSubDirectories := IncludeHiddenSubDirectories;
 
-   if fsMinSize in Options then
 
-     Task.FileSizeMin := FileSizeMin;
 
-   if fsMaxSize in Options then
 
-     Task.FileSizeMax := FileSizeMax;
 
-   if fsLastChangeAfter in Options then
 
-     Task.FFileTimeMin := {$IFDEF RTL220_UP}LastChangeAfter{$ELSE}DateTimeToFileDate(LastChangeAfter){$ENDIF};
 
-   if fsLastChangeBefore in Options then
 
-     Task.FFileTimeMax := {$IFDEF RTL220_UP}LastChangeBefore{$ELSE}DateTimeToFileDate(LastChangeBefore){$ENDIF};
 
-   Task.SynchronizationMode := SynchronizationMode;
 
-   Task.FOnEnterDirectory := OnEnterDirectory;
 
-   Task.OnTerminate := TaskTerminated;
 
-   FTasks.Add(Task);
 
-   if FRefCount > 0 then
 
-     _AddRef;
 
-   Result := Task;
 
- end;
 
- function TJclFileEnumerator.FillList(List: TStrings): TFileSearchTaskID;
 
- begin
 
-   List.BeginUpdate;
 
-   try
 
-     Result := ForEach(List.Append);
 
-   finally
 
-     List.EndUpdate;
 
-   end;
 
- end;
 
- function TJclFileEnumerator.ForEach(Handler: TFileHandlerEx): TFileSearchTaskID;
 
- var
 
-   Task: TEnumFileThread;
 
- begin
 
-   Task := TEnumFileThread(CreateTask);
 
-   Task.FFileHandlerEx := Handler;
 
-   Result := Task.ID;
 
-   {$IFDEF RTL210_UP}
 
-   Task.Suspended := False;
 
-   {$ELSE ~RTL210_UP}
 
-   Task.Resume;
 
-   {$ENDIF ~RTL210_UP}
 
- end;
 
- function TJclFileEnumerator.ForEach(Handler: TFileHandler): TFileSearchTaskID;
 
- var
 
-   Task: TEnumFileThread;
 
- begin
 
-   Task := TEnumFileThread(CreateTask);
 
-   Task.FFileHandler := Handler;
 
-   Result := Task.ID;
 
-   {$IFDEF RTL210_UP}
 
-   Task.Suspended := False;
 
-   {$ELSE ~RTL210_UP}
 
-   Task.Resume;
 
-   {$ENDIF ~RTL210_UP}
 
- end;
 
- function TJclFileEnumerator.GetRunningTasks: Integer;
 
- begin
 
-   Result := FTasks.Count;
 
- end;
 
- procedure TJclFileEnumerator.StopTask(ID: TFileSearchTaskID);
 
- var
 
-   Task: TEnumFileThread;
 
-   I: Integer;
 
- begin
 
-   for I := 0 to FTasks.Count - 1 do
 
-   begin
 
-     Task := TEnumFileThread(FTasks[I]);
 
-     if Task.ID = ID then
 
-     begin
 
-       Task.Terminate;
 
-       Break;
 
-     end;
 
-   end;
 
- end;
 
- procedure TJclFileEnumerator.StopAllTasks(Silently: Boolean = False);
 
- var
 
-   I: Integer;
 
- begin
 
-   for I := 0 to FTasks.Count - 1 do
 
-   begin
 
-     TEnumFileThread(FTasks[I]).FNotifyOnTermination := not Silently;
 
-     TEnumFileThread(FTasks[I]).Terminate;
 
-   end;
 
- end;
 
- procedure TJclFileEnumerator.TaskTerminated(Sender: TObject);
 
- begin
 
-   FTasks.Remove(Sender);
 
-   try
 
-     if Assigned(FOnTerminateTask) then
 
-       FOnTerminateTask(TEnumFileThread(Sender).ID, TEnumFileThread(Sender).Terminated);
 
-   finally
 
-     if FRefCount > 0 then
 
-       _Release;
 
-   end;
 
- end;
 
- function TJclFileEnumerator.GetNextTaskID: TFileSearchTaskID;
 
- begin
 
-   Result := FNextTaskID;
 
-   Inc(FNextTaskID);
 
- end;
 
- function TJclFileEnumerator.GetOnEnterDirectory: TFileHandler;
 
- begin
 
-   Result := FOnEnterDirectory;
 
- end;
 
- function TJclFileEnumerator.GetOnTerminateTask: TFileSearchTerminationEvent;
 
- begin
 
-   Result := FOnTerminateTask;
 
- end;
 
- function TJclFileEnumerator.GetSynchronizationMode: TFileEnumeratorSyncMode;
 
- begin
 
-   Result := FSynchronizationMode;
 
- end;
 
- procedure TJclFileEnumerator.SetOnEnterDirectory(
 
-   const Value: TFileHandler);
 
- begin
 
-   FOnEnterDirectory := Value;
 
- end;
 
- procedure TJclFileEnumerator.SetOnTerminateTask(
 
-   const Value: TFileSearchTerminationEvent);
 
- begin
 
-   FOnTerminateTask := Value;
 
- end;
 
- procedure TJclFileEnumerator.SetSynchronizationMode(
 
-   const Value: TFileEnumeratorSyncMode);
 
- begin
 
-   FSynchronizationMode := Value;
 
- end;
 
- function FileSearch: IJclFileEnumerator;
 
- begin
 
-   Result := TJclFileEnumerator.Create;
 
- end;
 
- function SamePath(const Path1, Path2: string): Boolean;
 
- begin
 
-   {$IFDEF MSWINDOWS}
 
-   Result := AnsiSameText(PathGetLongName(Path1), PathGetLongName(Path2));
 
-   {$ELSE ~MSWINDOWS}
 
-   Result := Path1 = Path2;
 
-   {$ENDIF ~MSWINDOWS}
 
- end;
 
- // add items at the end
 
- procedure PathListAddItems(var List: string; const Items: string);
 
- begin
 
-   ListAddItems(List, DirSeparator, Items);
 
- end;
 
- // add items at the end if they are not present
 
- procedure PathListIncludeItems(var List: string; const Items: string);
 
- var
 
-   StrList, NewItems: TStringList;
 
-   IndexNew, IndexList: Integer;
 
-   Item: string;
 
-   Duplicate: Boolean;
 
- begin
 
-   StrList := TStringList.Create;
 
-   try
 
-     StrToStrings(List, DirSeparator, StrList);
 
-     NewItems := TStringList.Create;
 
-     try
 
-       StrToStrings(Items, DirSeparator, NewItems);
 
-       for IndexNew := 0 to NewItems.Count - 1 do
 
-       begin
 
-         Item := NewItems.Strings[IndexNew];
 
-         Duplicate := False;
 
-         for IndexList := 0 to StrList.Count - 1 do
 
-           if SamePath(Item, StrList.Strings[IndexList]) then
 
-         begin
 
-           Duplicate := True;
 
-           Break;
 
-         end;
 
-         if not Duplicate then
 
-           StrList.Add(Item);
 
-       end;
 
-       List := StringsToStr(StrList, DirSeparator);
 
-     finally
 
-       NewItems.Free;
 
-     end;
 
-   finally
 
-     StrList.Free;
 
-   end;
 
- end;
 
- // delete multiple items
 
- procedure PathListDelItems(var List: string; const Items: string);
 
- var
 
-   StrList, RemItems: TStringList;
 
-   IndexRem, IndexList: Integer;
 
-   Item: string;
 
- begin
 
-   StrList := TStringList.Create;
 
-   try
 
-     StrToStrings(List, DirSeparator, StrList);
 
-     RemItems := TStringList.Create;
 
-     try
 
-       StrToStrings(Items, DirSeparator, RemItems);
 
-       for IndexRem := 0 to RemItems.Count - 1 do
 
-       begin
 
-         Item := RemItems.Strings[IndexRem];
 
-         for IndexList := StrList.Count - 1 downto 0 do
 
-           if SamePath(Item, StrList.Strings[IndexList]) then
 
-             StrList.Delete(IndexList);
 
-       end;
 
-       List := StringsToStr(StrList, DirSeparator);
 
-     finally
 
-       RemItems.Free;
 
-     end;
 
-   finally
 
-     StrList.Free;
 
-   end;
 
- end;
 
- // delete one item
 
- procedure PathListDelItem(var List: string; const Index: Integer);
 
- begin
 
-   ListDelItem(List, DirSeparator, Index);
 
- end;
 
- // return the number of item
 
- function PathListItemCount(const List: string): Integer;
 
- begin
 
-   Result := ListItemCount(List, DirSeparator);
 
- end;
 
- // return the Nth item
 
- function PathListGetItem(const List: string; const Index: Integer): string;
 
- begin
 
-   Result := ListGetItem(List, DirSeparator, Index);
 
- end;
 
- // set the Nth item
 
- procedure PathListSetItem(var List: string; const Index: Integer; const Value: string);
 
- begin
 
-   ListSetItem(List, DirSeparator, Index, Value);
 
- end;
 
- // return the index of an item
 
- function PathListItemIndex(const List, Item: string): Integer;
 
- var
 
-   StrList: TStringList;
 
-   IndexList: Integer;
 
- begin
 
-   StrList := TStringList.Create;
 
-   try
 
-     StrToStrings(List, DirSeparator, StrList);
 
-     Result := -1;
 
-     for IndexList := 0 to StrList.Count - 1 do
 
-       if SamePath(StrList.Strings[IndexList], Item) then
 
-     begin
 
-       Result := IndexList;
 
-       Break;
 
-     end;
 
-   finally
 
-     StrList.Free;
 
-   end;
 
- end;
 
- // additional functions to access the commandline parameters of an application
 
- // returns the name of the command line parameter at position index, which is
 
- // separated by the given separator, if the first character of the name part
 
- // is one of the AllowedPrefixCharacters, this character will be deleted.
 
- function ParamName(Index: Integer; const Separator: string;
 
-   const AllowedPrefixCharacters: string; TrimName: Boolean): string;
 
- var
 
-   S: string;
 
-   P: Integer;
 
- begin
 
-   if (Index > 0) and (Index <= ParamCount) then
 
-   begin
 
-     S := ParamStr(Index);
 
-     if Pos(Copy(S, 1, 1), AllowedPrefixCharacters) > 0 then
 
-       S := Copy(S, 2, Length(S) - 1);
 
-     P := Pos(Separator, S);
 
-     if P > 0 then
 
-       S := Copy(S, 1, P - 1);
 
-     if TrimName then
 
-       S := Trim(S);
 
-     Result := S;
 
-   end
 
-   else
 
-     Result := '';
 
- end;
 
- // returns the value of the command line parameter at position index, which is
 
- // separated by the given separator
 
- function ParamValue(Index: Integer; const Separator: string; TrimValue: Boolean): string;
 
- var
 
-   S: string;
 
-   P: Integer;
 
- begin
 
-   if (Index > 0) and (Index <= ParamCount) then
 
-   begin
 
-     S := ParamStr(Index);
 
-     P := Pos(Separator, S);
 
-     if P > 0 then
 
-       S := Copy(S, P + 1, Length(S) - P);
 
-     if TrimValue then
 
-       S := Trim(S);
 
-     Result := S;
 
-   end
 
-   else
 
-     Result := '';
 
- end;
 
- // seaches a command line parameter where the namepart is the searchname
 
- // and returns the value which is which by the given separator.
 
- // CaseSensitive defines the search type. if the first character of the name part
 
- // is one of the AllowedPrefixCharacters, this character will be deleted.
 
- function ParamValue(const SearchName: string; const Separator: string;
 
-   CaseSensitive: Boolean; const AllowedPrefixCharacters: string;
 
-   TrimValue: Boolean): string;
 
- var
 
-   Name: string;
 
-   SearchS: String;
 
-   I: Integer;
 
- begin
 
-   Result := '';
 
-   SearchS := Trim(SearchName);
 
-   for I := 1 to ParamCount do
 
-   begin
 
-     Name := ParamName(I, Separator, AllowedPrefixCharacters, True);
 
-     if (CaseSensitive and (Name = SearchS)) or
 
-        ((not CaseSensitive) and (CompareText(Name, SearchS) = 0)) then
 
-     begin
 
-       Result := ParamValue(I, Separator, TrimValue);
 
-       Exit;
 
-     end;
 
-   end;
 
- end;
 
- // seaches a command line parameter where the namepart is the searchname
 
- // and returns the position index. if no separator is defined, the full paramstr is compared.
 
- // CaseSensitive defines the search type. if the first character of the name part
 
- // is one of the AllowedPrefixCharacters, this character will be deleted.
 
- function ParamPos(const SearchName: string; const Separator: string;
 
-   CaseSensitive: Boolean; const AllowedPrefixCharacters: string): Integer;
 
- var
 
-   Name: string;
 
-   SearchS: string;
 
-   I: Integer;
 
- begin
 
-   Result := -1;
 
-   SearchS := Trim(SearchName);
 
-   for I := 1 to ParamCount do
 
-   begin
 
-     Name := ParamName(I, Separator, AllowedPrefixCharacters, True);
 
-     if (CaseSensitive and (Name = SearchS)) or
 
-        ((not CaseSensitive) and (CompareText(Name, SearchS) = 0)) then
 
-     begin
 
-       Result := I;
 
-       Exit;
 
-     end;
 
-   end;
 
- end;
 
- {$IFDEF UNITVERSIONING}
 
- initialization
 
-   RegisterUnitVersion(HInstance, UnitVersioning);
 
- finalization
 
-   UnregisterUnitVersion(HInstance);
 
- {$ENDIF UNITVERSIONING}
 
- end.
 
 
  |