Tải bản đầy đủ - 0 (trang)
Hack 30. Real Windows Shortcut Support

Hack 30. Real Windows Shortcut Support

Tải bản đầy đủ - 0trang

TheLNKfilesarebinarydatabrokenupintoaheaderfollowed

byafewoptionalblocksofdata.Theformatprovidesoffsets

thatmakeparsingiteasy.Thefollowingcodeisthebeginning

ofaLNKparser:



































publicclassLnkParser{



publicLnkParser(Filef)throwsException{





parse(f);



}



publicvoidparse(Filef)throwsException{





//readtheentirefileintoabytebuf





FileInputStreamfin=newFileInputStre





ByteArrayOutputStreambout=newByteAr





byte[]buff=newbyte[256];





while(true){







intn=fin.read(buff);







if(n==-1){break;}







bout.write(buff,0,n);





}





fin.close();





byte[]link=bout.toByteArray();



Theclassdefinesoneimportantmethod,parse(),whichaccepts

aFileobjectrepresentingtheLNKfile.Thefirststepistoload

theentirefileintoabytebuffer.



Ihaveseensomeversionsofthiscodeuseamorestream-oriented

approachwithloopsthatreadbytebybyte.SinceLNKfilesarealways

prettysmall(usuallyunder5k),Ifelttheextramemorywasworthitto

allowcleanercodeusingindexoffsets.



Nextcomestheheaderparsing:







//gettheflagsbyte

byteflags=link[0x14];























//getthefileattributesbyte

finalintfile_atts_offset=0x18;

bytefileatts=link[file_atts_offset];

byteis_dir_mask=(byte)0x10;

if((fileatts&is_dir_mask)>0){



is_dir=true;

}else{



is_dir=false;

}



Theheaderhasalotofvaluesinit,butweareonlyinterested

inthevaluesatbyte0x14(theflags)andat0x18(thefile

attributes).Eachofthesevaluesis8bits(abyte),whereeach

bitrepresentssomething,suchaswhethertheLNKpointstoa

fileoradirectory.Becausetheyarealwaysatthesameplace,

youcanjustjumpdirectlytotheminthearrayandstorethe

values.Toaccessabityouneedamask,whichisanumberthat

letsyouhideallofthebitsinavaluethatyoudon'twant,

leavingonlythebityoudowant.Touseit,youAND(abitwise

operationspecifiedbythe&character)thevalueandthemask

together.Thenyoucanjusttestifthefinalvalueisgreaterthan

zerotoseeifthatbitwasset.Ifthe4thbitofthefileattributes

byteisset(i.e.,isequalto1),thenthetargetofthisshortcutis

adirectory.Thefileattsandis_dir_maskareANDedtogether.If

thefinalvalueisgreaterthanzero,thenthebitmusthavebeen

setandtheprogramsetstheis_dirvariabletotrue;otherwise,

itsetsis_dirtofalse.







//iftheshellsettingsarepresent,skipthem

finalintshell_offset=0x4c;











}



intshell_len=0;

if((flags&0x1)>0){

//theplus2accountsforthelengthmarkeritself

shell_len=bytes2short(link,shell_offset)+2;



LNKfileshaveanoptionalblockforshellsettings,whichare

irrelevantforthepurposesofgettingthetargetpath.Ifthe

shellsettingsarepresent(indicatedbythe0thbitoftheflags),

thenjumptotheshellblock,getitslengthfromthenext2

bytes,andthenskiptotheend.Theif((flags&0x1)>0)section

ANDstheflagsvalueandamasktogetthe0thbitandseeif

thereisashellblock.Iftheshellblockisnotpresent,thenyou

canjustsettheoffsetto0andcontinue.bytes2short()isasimple

routinethatconvertstwobytesintoashort.







//gettothefileblock

intfile_start=0x4c+shell_len;













//getthelocalvolumeandlocalsystemvalues

intlocal_sys_off=link[file_start+0x10]+file_start;

real_file=getNullDelimitedString(link,local_sys_off);

p("realfilename="+real_file);



Thefileblockstarts0x4c(76inhexadecimal)bytesafterthe

previousblock(ortheheadersiftherewasnopreviousblock).

Onceyouareatthefileblock,youcanpulloutthe0x10thbyte

tofindtheoffsettothelocalsystemtargetfilename.



Ifthedirectorywasonanetworkdrive,youwouldhavetolookfora

differentoffset,butI'veassumedthefilewaslocaltokeepthecode

simple.Amorerobustimplementationwouldsupportbothlocaland

remotefiles.



Onceyouhavetheoffsettothefilename,pullitoutasanulldelimitedstringandsaveitinthereal_filevariable.

Ireferencedthesetwoutilityfunctionsearlier.

getNullDelimitedStringlooksthroughthebytearraystartingatthe

requestedoffset.Whenitfindsanullvalue(0),itwillreturna

substringfromthestartingoffsettothelastvalidcharacter;

thatsubstringcontainsthefilepath.bytes2shortusesbit-shifting

toturntwobytesintoashortinteger:





































staticStringgetNullDelimitedString(byte[]bytes,int



intlen=0;



//countbytesuntilthenullcharacter(0)



while(true){





if(bytes[off+len]==0){







break;





}





len++;



}





returnnewString(bytes,off,len);



}



//converttwobytesintoashort



//note,thisislittle-endianbecauseit'sfor



//Intel-onlyOS.



staticintbytes2short(byte[]bytes,intoff){





returnbytes[off]|(bytes[off+1]<<8);





}



Ifyoulearnedlow-levelprogrammingonRISCmachineslikeIdid,you

mightbesurprisedthatthesecondbyteisbeingshiftedinsteadofthe

first.Youmustrememberthatshort-cutfilesaredesignedforWindows,

whichonlyrunsonlittle-endianprocessors.Afterwritingthishack,I



rememberedhowmuchIhatebitflippingandbytemanipulation.I

probablyswitchedtoJavasoearlysothatIwouldneverhavetodeal

withdataatthebytelevelagain!



Now,theclassjustneedssomegetterstolettheoutsideworld

usetheparser.Thesetwomethodsexposetheis_dirand

real_filevariablesthattheparse()methodsets:



















privatebooleanis_dir;

publicbooleanisDirectory(){



returnis_dir;

}

privateStringreal_file;

publicStringgetRealFilename(){

returnreal_file;

}



LNKParserwritten,it'snowtimetohandtheshortcut

informationovertothefilechooser.JFileChoosersdividethefile

manipulationdutiesintotwohelperclasses.TheFileViewclass

controlsthelookoffiles[Hack#29],suchasnames,icons,

etc.TheFileSystemViewprovidestheJFileChooserwithinformation

aboutthefilesystemitself,includingwhichfilesaredirectories.

Forcontrollingdirectories,thetwomethodsimplementedhere

areparticularlyrelevant:





publicclassShortcutFileSystemViewextendsFileSystemV















publicBooleanisTraversable(Filef){



if(isDirLink(f)){





returnnewBoolean(true);



}



returnsuper.isTraversable(f);



















}

publicFile[]getFiles(Filedir,booleanuseFileHiding)



if(isDirLink(dir)){





dir=getRealFile(dir);



}



returnsuper.getFiles(dir,useFileHiding);

}



TheJFileChooserwillcallisTraversable()oneachfiletoseeifitis

reallyafolder.Thisdoesnotcontrolwhetheritusesafolder

icon,butwhethertheusercanopenupandfollowthefileasa

directory.ThisimplementationsimplycallstheisDirLink()

method(detailedshortly)totestthecurrentfile.Ifit'snota

shortcutthenitdeferstotheparentclass.

getFiles()returnsthedirectorylistingofthegivenfile.

JFileChooserprovidesthistoletdevelopersmesswiththefile



listing.Youcouldusethistopreventhiddenfilesfromshowing

ortorestricttheuserfromareasofthefilesystemthey

shouldn'tbeallowedtoaccess.Forthishack,thegetFiles()

methodwilllookforshortcutsandreplacethemwiththereal

filestheypointtobycallingthegetrealFile()method:



























privatebooleanisDirLink(Filef){



try{





if(f.getName().toLowerCase().endsWith("







if(newLnkParser(f).isDirectory







returntrue;







}





}



}catch(Exceptionex){





System.out.println("ex:"+ex);





ex.printStackTrace();



}



returnfalse;







}























privateFilegetRealFile(Filefile){



try{





returnnewFile(newLnkParser(file).get



}catch(Exceptionex){





System.out.println("ex:"+ex);





ex.printStackTrace();





returnnull;



}

}



isDirLink()andgetrealFile()areverysimple.Theyjustcallthe



appropriatefunctionontheLnkParserandcatchexceptions.By

movingalloftheactualLNKhandlingcodeintotheLnkParser,

youcouldaddsupporteasilytootherkindsoflinksherejustby

addingafewmoreifstatements.

Tosupportdrawingtheicons,justmodifytheShortcutFileView

fromtheprevioushacktocalltheLnkParseraswell:



















publicbooleanisDirLink(Filef){



try{





if(f.getName().toLowerCase().endsWith("





LnkParserparser=newLnkParser(f);





if(parser.isDirectory()){







returntrue;





}



}















}catch(Exceptionex){



System.out.println("exception:"+ex.getMessag



ex.printStackTrace();

}

returnfalse;



}



Andfinally,here'satestclassthatwillbuildanewshortcut

enabledfilechooser.Itcreatesanormalfilechooser,andthen

setstheFileSystemViewtothenewshortcutsubclass.Italsosets

themodifiedversionoftheShortcutFileView:





















publicclassShortcutTest{



publicstaticvoidmain(String[]args)throwsE





FileSystemViewfsv=newShortcutFileSy





JFileChooserchooser=newJFileChooser





chooser.setFileSystemView(fsv);





chooser.setFileView(newShortcutFileVie





chooser.showOpenDialog(null);



}

}



Figure4-5showstheJFileChooserdisplayingashortcutthatwill

behavelikearealWindowsshortcutwhenclicked.



Figure4-5.AJFileChooserwithaliveshortcut



Hack31.AddImagePreviewtoFileChoosers



Thishackwillshowyouhowtoaddanimagepreviewer

toaJFileChooser,anditwillsetyouonthewaytoward

buildingyourowncustomizations.

We'vealreadytalkedaboutJFileChooser'snumerouslimitations.

Notsurprisingly,manyapplicationshavetheirowncustom

choosersandextensionstosupportthingslikeimagepreviews.

ThestandardJFileChooserwasdesignedtomimiconlythemost

commonfeatures,butitdoesprovideawaytoaddyourown

enhancements.

ThestandardJFileChooserlookslikemostnativefilechoosers.It

hasadirectoryselector,alistoffiles,andselectandclose

buttons.Theremayalsobeatoolbarofsorts.Ifyouwantto

buildyourowncustomizedfilechooser,youcoulddoitthe

samewayplatform-specificfilechoosersare

implementedthroughL&Fcode.Thiswouldentailsubclassing

javax.swing.plaf.basic.BasicFileChooserUI,workingaroundthe

privatemethods,andpossiblyreimplementingthewholething,

noneofwhichiseasyorfun.Fortunately,theJFileChooserAPI

providesasimpleextensionhookintheformofthesetAccesory()

method.ThismethodletsyouaddanyJComponenttoanexisting

JFileChooser,therebyaddingyourownfeatureswithoutmucking

aroundinfilechoosercode.

Inthishack,you'lllearnhowtocreateanimagepreviewer.This

isacomponentthatshowsathumbnailviewofthecurrently

selectedfileifthatfileisanimage.Itwillalsoshowthe

dimensionsoftheimage.BecauseJava1.4providesrobust

imagesupportwiththejavax.imageioAPI,thisshouldbepretty

easy.ThefirststepisacustomImagePreviewcomponent:











publicclassImagePreviewextendsJPanelimplements



privateJFileChooserjfc;



privateImageimg;



























publicImagePreview(JFileChooserjfc){



this.jfc=jfc;



Dimensionsz=newDimension(200,200);



setPreferredSize(sz);

}



ThecodedefinestheImagePreviewclass,asubclassofJPanel.I've

hardcodedthesizeofthecomponentto200x200largeenough

totellwhattheimageis,butsmallenoughnottoimpactthe

filechooserverymuch.

ImagePreviewalsoimplementsPropertyChangeListenersoitcandetect



whentheuserselectsafile:























publicvoidpropertyChange(PropertyChangeEventevt){



try{





System.out.println("updating");





Filefile=jfc.getSelectedFile(





updateImage(file);



}catch(IOExceptionex){





System.out.println(ex.getMessage());





ex.printStackTrace();



}

}



PropertyChangeisthesinglemethodofthePropertyChangeListener



interface.ThiswillbecalledbytheJFileChoosereachtimethe

userselects(ordeselects)afile.Whenthathappens,

ImagePreviewwillcallitsupdateImage()methodonthatfile:



Tài liệu bạn tìm kiếm đã sẵn sàng tải về

Hack 30. Real Windows Shortcut Support

Tải bản đầy đủ ngay(0 tr)

×