/* Ċ Ġ* ĠCopyright Ġ 2 0 1 9 ĠThe ĠAndroid ĠOpen ĠSource ĠProject Ċ Ġ* Ċ Ġ* ĠLicensed Ġunder Ġthe ĠApache ĠLicense , ĠVersion Ġ 2 . 0 Ġ( the Ġ" License "); Ċ Ġ* Ġyou Ġmay Ġnot Ġuse Ġthis Ġfile Ġexcept Ġin Ġcompliance Ġwith Ġthe ĠLicense . Ċ Ġ* ĠYou Ġmay Ġobtain Ġa Ġcopy Ġof Ġthe ĠLicense Ġat Ċ Ġ* Ċ Ġ* ĠĠĠĠĠ Ġhttp :// www . apache . org / licenses / LICENSE - 2 . 0 Ċ Ġ* Ċ Ġ* ĠUnless Ġrequired Ġby Ġapplicable Ġlaw Ġor Ġagreed Ġto Ġin Ġwriting , Ġsoftware Ċ Ġ* Ġdistributed Ġunder Ġthe ĠLicense Ġis Ġdistributed Ġon Ġan Ġ" AS ĠIS " ĠBASIS , Ċ Ġ* ĠWITHOUT ĠWARRANTIES ĠOR ĠCONDITIONS ĠOF ĠANY ĠKIND , Ġeither Ġexpress Ġor Ġimplied . Ċ Ġ* ĠSee Ġthe ĠLicense Ġfor Ġthe Ġspecific Ġlanguage Ġgoverning Ġpermissions Ġand Ċ Ġ* Ġlimitations Ġunder Ġthe ĠLicense . Ċ Ġ*/ Ċ package Ġcom . is lam vers ity . d agger core . sqlite helper Ċ Ċ import Ġandroid . content . Context Ċ import Ġandroid . os . Build Ċ import Ġandroid . util . Log Ċ import Ġandroidx . annotation . Requires Api Ċ import Ġandroidx . sqlite . db . Support SQLite Database Ċ import Ġandroidx . sqlite . db . Support SQLite Open Helper Ċ import Ġjava . io .* Ċ import Ġjava . nio . ByteBuffer Ċ import Ġjava . nio . channels . Channels Ċ import Ġjava . nio . channels . File Channel Ċ import Ġjava . nio . channels . Readable Byte Channel Ċ import Ġjava . util . concurrent . Callable Ċ import Ġjava . util . zip . Zip Entry Ċ import Ġjava . util . zip . Zip InputStream Ċ Ċ private Ġconst Ġval ĠLOG _ TAG Ġ= Ġ" SQLite Copy Open Helper " ĊĊ Ċ /** Ċ Ġ* ĠAn Ġopen Ġhelper Ġthat Ġwill Ġcopy Ġ& Ġopen Ġa Ġpre - pop ulated Ġdatabase Ġif Ġit Ġdoesn 't Ġexists Ġin Ġinternal Ċ Ġ* Ġstorage . Ċ Ġ*/ Ċ class ĠSQLite Copy Open Helper ( ĊĠĠĠ Ġprivate Ġval ĠmContext : ĠContext , ĊĠĠĠ Ġprivate Ġval Ġm Copy From Asset Path : ĠString ?, ĊĠĠĠ Ġprivate Ġval Ġm Copy FromFile : ĠFile ?, ĊĠĠĠ Ġprivate Ġval Ġm Copy From InputStream : ĠCallable < InputStream > ?, ĊĠĠĠ Ġprivate Ġval Ġm Database Version : ĠInt , ĊĠĠĠ Ġprivate Ġval Ġm Delegate : ĠSupport SQLite Open Helper Ċ ) Ġ: ĠSupport SQLite Open Helper Ġ{ ĊĠĠĠ Ġprivate Ġvar Ġm Verified Ġ= Ġfalse ĊĠĠĠ Ġoverride Ġfun Ġget Database Name (): ĠString ? Ġ{ ĊĠĠĠĠĠĠĠ Ġreturn Ġm Delegate . database Name ĊĠĠĠ Ġ} ĊĊĠĠĠ Ġ@ Requires Api ( api Ġ= ĠBuild . VERSION _ CODES . J EL LY _ BE AN ) ĊĠĠĠ Ġoverride Ġfun Ġset Write A head Logging Enabled ( enabled : ĠBoolean ) Ġ{ ĊĠĠĠĠĠĠĠ Ġm Delegate . set Write A head Logging Enabled ( enabled ) ĊĠĠĠ Ġ} ĊĊĠĠĠ Ġ@ Synchron ized ĊĠĠĠ Ġoverride Ġfun Ġget Writable Database (): ĠSupport SQLite Database Ġ{ ĊĠĠĠĠĠĠĠ Ġif Ġ(! m Verified ) Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠ Ġverify Database File () ĊĠĠĠĠĠĠĠĠĠĠĠ Ġm Verified Ġ= Ġtrue ĊĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠĠĠ Ġreturn Ġm Delegate . writable Database ĊĠĠĠ Ġ} ĊĊĠĠĠ Ġ@ Synchron ized ĊĠĠĠ Ġoverride Ġfun Ġget Readable Database (): ĠSupport SQLite Database Ġ{ ĊĠĠĠĠĠĠĠ Ġif Ġ(! m Verified ) Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠ Ġverify Database File () ĊĠĠĠĠĠĠĠĠĠĠĠ Ġm Verified Ġ= Ġtrue ĊĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠĠĠ Ġreturn Ġm Delegate . readable Database ĊĠĠĠ Ġ} ĊĊĠĠĠ Ġ@ Synchron ized ĊĠĠĠ Ġoverride Ġfun Ġclose () Ġ{ ĊĠĠĠĠĠĠĠ Ġm Delegate . close () ĊĠĠĠĠĠĠĠ Ġm Verified Ġ= Ġfalse ĊĠĠĠ Ġ} ĊĊĠĠĠ Ġprivate Ġfun Ġverify Database File () Ġ{ ĊĠĠĠĠĠĠĠ Ġval Ġdatabase Name Ġ= Ġdatabase Name ĊĠĠĠĠĠĠĠ Ġval Ġdatabase File Ġ= ĠmContext . get Database Path ( database Name ) ĊĠĠĠĠĠĠĠ Ġval Ġcopy Lock Ġ= ĠCopy Lock ( database Name !! , ĠmContext . files Dir , Ġtrue ) ĊĠĠĠĠĠĠĠ Ġtry Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠ Ġ// ĠAc quire Ġa Ġcopy Ġlock , Ġthis Ġlock Ġworks Ġacross Ġthreads Ġand Ġprocesses , Ġprevent ing ĊĠĠĠĠĠĠĠĠĠĠĠ Ġ// Ġconcurrent Ġcopy Ġattempts Ġfrom Ġoccur ring . ĊĠĠĠĠĠĠĠĠĠĠĠ Ġcopy Lock . lock () ĊĠĠĠĠĠĠĠĠĠĠĠ Ġif Ġ(! database File . exists ()) Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġtry Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ// ĠNo Ġdatabase Ġfile Ġfound , Ġcopy Ġand Ġbe Ġdone . ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġcopy Database File ( database File ) ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġreturn ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ} Ġcatch Ġ( e : ĠIOException ) Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġthrow ĠRuntimeException (" Unable Ġto Ġcopy Ġdatabase Ġfile .", Ġe ) ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠĠĠĠĠĠĠ Ġ} ĊĊĠĠĠĠĠĠĠĠĠĠĠ Ġ// ĠA Ġdatabase Ġfile Ġis Ġpresent , Ġcheck Ġif Ġwe Ġneed Ġto Ġre - copy Ġit . ĊĠĠĠĠĠĠĠĠĠĠĠ Ġval Ġcurrent Version : ĠInt Ġ= Ġtry Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġread Version ( database File ) ĊĠĠĠĠĠĠĠĠĠĠĠ Ġ} Ġcatch Ġ( e : ĠIOException ) Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ ĠLog . w ( LOG _ TAG , Ġ" Unable Ġto Ġread Ġdatabase Ġversion .", Ġe ) ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġreturn ĊĠĠĠĠĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠĠĠĠĠĠĠ Ġif Ġ( current Version Ġ== Ġm Database Version ) Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġreturn ĊĠĠĠĠĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠĠĠĠĠĠĠ Ġif Ġ( current Version Ġ<= Ġm Database Version ) Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ// ĠFrom Ġthe Ġcurrent Ġversion Ġto Ġthe Ġdesired Ġversion Ġa Ġmigration Ġis Ġrequired , Ġi . e . ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ// Ġwe Ġwon 't Ġbe Ġperforming Ġa Ġcopy Ġdestruct ive Ġmigration . ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġreturn ĊĠĠĠĠĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠĠĠĠĠĠĠ Ġif Ġ( mContext . delete Database ( database Name )) Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġtry Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġcopy Database File ( database File ) ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ} Ġcatch Ġ( e : ĠIOException ) Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ// ĠWe Ġare Ġmore Ġfor g iving Ġcopying Ġa Ġdatabase Ġon Ġa Ġdestruct ive Ġmigration Ġsince ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ// Ġthere Ġis Ġalready Ġa Ġdatabase Ġfile Ġthat Ġcan Ġbe Ġopened . ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ ĠLog . w ( LOG _ TAG , Ġ" Unable Ġto Ġcopy Ġdatabase Ġfile .", Ġe ) ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠĠĠĠĠĠĠ Ġ} Ġelse Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ ĠLog . w ( ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ ĠLOG _ TAG , Ġ" Failed Ġto Ġdelete Ġdatabase Ġfile Ġ(" ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ+ Ġdatabase Name Ġ+ Ġ") Ġfor Ġa Ġcopy Ġdestruct ive Ġmigration ." ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ) ĊĠĠĠĠĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠĠĠ Ġ} Ġfinally Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠ Ġcopy Lock . unlock () ĊĠĠĠĠĠĠĠ Ġ} ĊĠĠĠ Ġ} ĊĊĠĠĠ Ġprivate Ġfun Ġcopy Database File ( destination File : ĠFile ) Ġ{ ĊĠĠĠĠĠĠĠ Ġval Ġinput : ĠRead able Byte Channel ĊĠĠĠĠĠĠĠ Ġif Ġ( m Copy From Asset Path Ġ!= Ġnull ) Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠ Ġinput Ġ= ĠChannels . new Channel ( mContext . assets . open ( m Copy From Asset Path )) ĊĠĠĠĠĠĠĠ Ġ} Ġelse Ġif Ġ( m Copy FromFile Ġ!= Ġnull ) Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠ Ġinput Ġ= ĠFileInputStream ( m Copy FromFile ). channel ĊĠĠĠĠĠĠĠ Ġ} Ġelse Ġif Ġ( m Copy From InputStream Ġ!= Ġnull ) Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠ Ġval ĠinputStream : ĠInputStream ĊĠĠĠĠĠĠĠĠĠĠĠ ĠinputStream Ġ= Ġtry Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġm Copy From InputStream . call () ĊĠĠĠĠĠĠĠĠĠĠĠ Ġ} Ġcatch Ġ( e : ĠException ) Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġthrow ĠIOException (" inputStream Callable Ġexception Ġon Ġcall ", Ġe ) ĊĠĠĠĠĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠĠĠĠĠĠĠ Ġinput Ġ= ĠChannels . new Channel ( inputStream ) ĊĠĠĠĠĠĠĠ Ġ} Ġelse Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠ Ġthrow ĠIllegalStateException ( ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ" copyFrom Asset Path , Ġcopy FromFile Ġand Ġ" ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ+ Ġ" copyFrom InputStream Ġare Ġall Ġnull !" ĊĠĠĠĠĠĠĠĠĠĠĠ Ġ) ĊĠĠĠĠĠĠĠ Ġ} ĊĊĠĠĠĠĠĠĠ Ġ// ĠAn Ġintermediate Ġfile Ġis Ġused Ġso Ġthat Ġwe Ġnever Ġend Ġup Ġwith Ġa Ġhalf - copied Ġdatabase Ġfile ĊĠĠĠĠĠĠĠ Ġ// Ġin Ġthe Ġinternal Ġdirectory . ĊĠĠĠĠĠĠĠ Ġval Ġintermediate File Ġ= ĠFile . create TempFile ( ĊĠĠĠĠĠĠĠĠĠĠĠ Ġ" room - copy - helper ", Ġ". tmp ", ĠmContext . cacheDir ĊĠĠĠĠĠĠĠ Ġ) ĊĠĠĠĠĠĠĠ Ġintermediate File . delete On Exit () ĊĠĠĠĠĠĠĠ Ġval Ġoutput Ġ= ĠFileOutputStream ( intermediate File ). channel ĊĠĠĠĠĠĠĠ Ġunpack Zip ( input , Ġoutput ) Ċ // ĠĠĠĠĠĠĠ Ġcopy ( input , Ġoutput ) ĊĠĠĠĠĠĠĠ Ġval Ġparent Ġ= Ġdestination File . parent File ĊĠĠĠĠĠĠĠ Ġif Ġ( parent Ġ!= Ġnull Ġ&& Ġ! parent . exists () Ġ&& Ġ! parent . mkdir s ()) Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠ Ġthrow ĠIOException ( ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ" Failed Ġto Ġcreate Ġdirectories Ġfor Ġ" ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ+ Ġdestination File . absolute Path ĊĠĠĠĠĠĠĠĠĠĠĠ Ġ) ĊĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠĠĠ Ġif Ġ(! intermediate File . rename To ( destination File )) Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠ Ġthrow ĠIOException ( ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ" Failed Ġto Ġmove Ġintermediate Ġfile Ġ(" ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ+ Ġintermediate File . absolute Path Ġ+ Ġ") Ġto Ġdestination Ġ(" ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ+ Ġdestination File . absolute Path Ġ+ Ġ"). " ĊĠĠĠĠĠĠĠĠĠĠĠ Ġ) ĊĠĠĠĠĠĠĠ Ġ} ĊĠĠĠ Ġ} Ċ } Ċ Ċ /** Ċ Ġ* ĠReads Ġthe Ġuser Ġversion Ġnumber Ġout Ġof Ġthe Ġdatabase Ġheader Ġfrom Ġthe Ġgiven Ġfile . Ċ Ġ* Ċ Ġ* Ġ@ param Ġdatabase File Ġthe Ġdatabase Ġfile . Ċ Ġ* Ġ@ return Ġthe Ġdatabase Ġversion Ċ Ġ* Ġ@ throws ĠIOException Ġif Ġsomething Ġgoes Ġwrong Ġreading Ġthe Ġfile , Ġsuch Ġas Ġbad Ġdatabase Ġheader Ġor Ċ Ġ* Ġmissing Ġpermissions . Ċ Ġ* Ċ Ġ* Ġ@ see Ġ[ User ĠVersion Ċ Ġ* ĠNumber ]( https :// www . sqlite . org / file format . html . user _ version _ number ). Ċ Ġ*/ Ċ private Ġfun Ġread Version ( database File : ĠFile ): ĠInt Ġ{ ĊĠĠĠ Ġvar Ġinput : ĠFile Channel ? Ġ= Ġnull ĊĠĠĠ Ġreturn Ġtry Ġ{ ĊĠĠĠĠĠĠĠ Ġval Ġbuffer Ġ= ĠByteBuffer . allocate ( 4 ) ĊĠĠĠĠĠĠĠ Ġinput Ġ= ĠFileInputStream ( database File ). channel ĊĠĠĠĠĠĠĠ Ġinput . try Lock ( 6 0 , Ġ 4 , Ġtrue ) ĊĠĠĠĠĠĠĠ Ġinput . position ( 6 0 ) ĊĠĠĠĠĠĠĠ Ġval Ġread Ġ= Ġinput . read ( buffer ) ĊĠĠĠĠĠĠĠ Ġif Ġ( read Ġ!= Ġ 4 ) Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠ Ġthrow ĠIOException (" Bad Ġdatabase Ġheader , Ġunable Ġto Ġread Ġ 4 Ġbytes Ġat Ġoffset Ġ 6 0 ") ĊĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠĠĠ Ġbuffer . rewind () ĊĠĠĠĠĠĠĠ Ġbuffer . int Ġ// ĠByteBuffer Ġis Ġbig - endian Ġby Ġdefault ĊĠĠĠ Ġ} Ġfinally Ġ{ ĊĠĠĠĠĠĠĠ Ġinput ?. close () ĊĠĠĠ Ġ} Ċ } Ċ Ċ /** Ċ Ġ* ĠCop ies Ġdata Ġfrom Ġthe Ġinput Ġchannel Ġto Ġthe Ġoutput Ġfile Ġchannel . Ċ Ġ* Ċ Ġ* Ġ@ param Ġinput Ġ Ġthe Ġinput Ġchannel Ġto Ġcopy . Ċ Ġ* Ġ@ param Ġoutput Ġthe Ġoutput Ġchannel Ġto Ġcopy . Ċ Ġ* Ġ@ throws ĠIOException Ġif Ġthere Ġis Ġan ĠI / O Ġerror . Ċ Ġ*/ Ċ private Ġfun Ġcopy ( input : ĠRead able Byte Channel , Ġoutput : ĠFile Channel ) Ġ{ ĊĠĠĠ Ġtry Ġ{ ĊĠĠĠĠĠĠĠ Ġif Ġ( Build . VERSION . SDK _ INT Ġ> ĠBuild . VERSION _ CODES . M ) Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠ Ġoutput . transfer From ( input , Ġ 0 , ĠLong . MAX _ VALUE ) ĊĠĠĠĠĠĠĠ Ġ} Ġelse Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠ Ġval ĠinputStream Ġ= ĠChannels . new InputStream ( input ) ĊĠĠĠĠĠĠĠĠĠĠĠ Ġval ĠoutputStream Ġ= ĠChannels . new OutputStream ( output ) ĊĠĠĠĠĠĠĠĠĠĠĠ Ġvar Ġlength : ĠInt ĊĠĠĠĠĠĠĠĠĠĠĠ Ġval Ġbuffer Ġ= ĠByteArray ( 1 0 2 4 Ġ* Ġ 4 ) ĊĠĠĠĠĠĠĠĠĠĠĠ Ġwhile Ġ( inputStream . read ( buffer ). also Ġ{ Ġlength Ġ= Ġit Ġ} Ġ> Ġ 0 ) Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ ĠoutputStream . write ( buffer , Ġ 0 , Ġlength ) ĊĠĠĠĠĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠĠĠ Ġoutput . force ( false ) ĊĠĠĠ Ġ} Ġfinally Ġ{ ĊĠĠĠĠĠĠĠ Ġinput . close () ĊĠĠĠĠĠĠĠ Ġoutput . close () ĊĠĠĠ Ġ} Ċ } Ċ Ċ // this Ġmethod Ġcan Ġbe Ġmuch Ġfaster Ġand Ġmore Ġreliable Ċ // Ġalso Ġwe Ġcan Ġuse ĠOk IO Ġfor Ġbetter Ġperformance Ċ fun Ġunpack Zip ( input : ĠRead able Byte Channel , Ġoutput : ĠFile Channel ): ĠBoolean Ġ{ ĊĠĠĠ ĠZip InputStream ( Channels . new InputStream ( input )). use Ġ{ Ġz is Ġ-> ĊĠĠĠĠĠĠĠ Ġtry Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠ Ġval Ġze : ĠZip Entry Ġ= Ġz is . next Entry ĊĠĠĠĠĠĠĠĠĠĠĠ Ġval Ġfilename : ĠString Ġ= Ġze . name ĊĊĊĠĠĠĠĠĠĠĠĠĠĠ Ġval Ġbuffer Ġ= ĠByteArray ( 1 0 2 4 Ġ* Ġ 4 ) ĊĠĠĠĠĠĠĠĠĠĠĠ Ġvar Ġcount : ĠInt ĊĊĠĠĠĠĠĠĠĠĠĠĠ Ġval Ġfout Ġ= ĠChannels . new OutputStream ( output ) ĊĊĠĠĠĠĠĠĠĠĠĠĠ Ġwhile Ġ( z is . read ( buffer ). also Ġ{ Ġcount Ġ= Ġit Ġ} Ġ!= Ġ- 1 ) Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġfout . write ( buffer , Ġ 0 , Ġcount ) ĊĠĠĠĠĠĠĠĠĠĠĠ Ġ} ĊĊĠĠĠĠĠĠĠĠĠĠĠ Ġoutput . force ( false ) ĊĠĠĠĠĠĠĠĠĠĠĠ Ġz is . close Entry () ĊĠĠĠĠĠĠĠ Ġ} finally Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠ Ġoutput . close () ĊĠĠĠĠĠĠĠĠĠĠĠ Ġinput . close () ĊĠĠĠĠĠĠĠ Ġ} ĊĠĠĠ Ġ} ĊĠĠĠ Ġreturn Ġtrue Ċ } Ċ