Last active
December 7, 2020 17:46
-
-
Save Madina-S/35850afb0adfac9e2bd3172c53571eb3 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import okhttp3.internal.closeQuietly | |
import org.apache.commons.io.IOUtils | |
import uz.gid.updater.ZipUtil.zipBytes | |
import java.io.* | |
import java.nio.file.Files | |
import java.util.zip.ZipEntry | |
import java.util.zip.ZipInputStream | |
import java.util.zip.ZipOutputStream | |
object ZipUtil { | |
fun getDifference(old: ByteArray, new: ByteArray): ByteArray { | |
val oldZipFileSet: MutableSet<String> = LinkedHashSet() | |
val newZipFileSet: MutableSet<String> = LinkedHashSet() | |
val oldZipInputStreamSet = HashMap<String, InputStream>() | |
val newZipInputStreamSet = HashMap<String, InputStream>() | |
run { | |
val oldZipInputStream = ZipInputStream(ByteArrayInputStream(old)) | |
val newZipInputStream = ZipInputStream(ByteArrayInputStream(new)) | |
var entry: ZipEntry? = null | |
var fileName: String | |
var byteArrayInputStream: ByteArrayInputStream | |
while (oldZipInputStream.nextEntry?.let { entry = it } != null) { | |
if (entry!!.isDirectory.not()) { | |
fileName = entry!!.name | |
oldZipFileSet.add(fileName) | |
byteArrayInputStream = ByteArrayInputStream(IOUtils.toByteArray(oldZipInputStream.buffered())) | |
oldZipInputStreamSet[fileName] = byteArrayInputStream | |
} | |
} | |
while (newZipInputStream.nextEntry?.let { entry = it } != null) { | |
if (entry!!.isDirectory.not()) { | |
fileName = entry!!.name | |
newZipFileSet.add(fileName) | |
byteArrayInputStream = ByteArrayInputStream(IOUtils.toByteArray(newZipInputStream.buffered())) | |
newZipInputStreamSet[fileName] = byteArrayInputStream | |
} | |
} | |
oldZipInputStream.closeQuietly() | |
newZipInputStream.closeEntry() | |
} | |
val byteArrayOutputStream = ByteArrayOutputStream() | |
ZipOutputStream(byteArrayOutputStream).use { out -> | |
var zipEntry: Iterator<String> = oldZipFileSet.iterator() | |
var oldZipInputStream: InputStream | |
var newZipInputStream: InputStream | |
while (zipEntry.hasNext()) { | |
val name = zipEntry.next() | |
if (!newZipFileSet.contains(name)) { | |
println("$name not found in the new zip") | |
//file removed, there is no need to handle it | |
continue | |
} | |
try { | |
newZipFileSet.remove(name) | |
newZipInputStream = newZipInputStreamSet[name]!! | |
oldZipInputStream = oldZipInputStreamSet[name]!! | |
if (!streamsEqual(oldZipInputStream, newZipInputStream)) { | |
println("$name is changed") | |
newZipInputStream.reset() | |
write(out, name, newZipInputStream) | |
} | |
newZipInputStream.closeQuietly() | |
oldZipInputStream.closeQuietly() | |
} catch (e: Exception) { | |
println("$name: IO Error $e") | |
e.printStackTrace() | |
} | |
} | |
zipEntry = newZipFileSet.iterator() | |
while (zipEntry.hasNext()) { | |
val name = zipEntry.next() | |
println("$name not found in the old zip") | |
write(out, name, newZipInputStreamSet[name]!!) | |
} | |
val buffer = byteArrayOutputStream.toByteArray() | |
byteArrayOutputStream.closeQuietly() | |
return buffer | |
} | |
} | |
fun zipBytes(filename: String, input: ByteArray) { | |
val zos = ZipOutputStream(FileOutputStream(File(filename))) | |
val zis = ZipInputStream(ByteArrayInputStream(input)) | |
var entry: ZipEntry? = null | |
while (zis.nextEntry?.let { entry = it } != null) { | |
zos.putNextEntry(entry!!) | |
IOUtils.copy(zis.buffered(), zos) | |
} | |
zos.close() | |
} | |
private fun write(out: ZipOutputStream, entryName: String, inputStream: InputStream) { | |
val zipEntry = ZipEntry(entryName) | |
out.putNextEntry(zipEntry) | |
IOUtils.copy(inputStream, out) | |
out.closeEntry() | |
} | |
@Throws(IOException::class) | |
private fun streamsEqual(stream1: InputStream, stream2: InputStream): Boolean { | |
val buf1 = ByteArray(4096) | |
val buf2 = ByteArray(4096) | |
var done1 = false | |
var done2 = false | |
return try { | |
while (!done1) { | |
var off1 = 0 | |
var off2 = 0 | |
while (off1 < buf1.size) { | |
val count = stream1.read(buf1, off1, buf1.size - off1) | |
if (count < 0) { | |
done1 = true | |
break | |
} | |
off1 += count | |
} | |
while (off2 < buf2.size) { | |
val count = stream2.read(buf2, off2, buf2.size - off2) | |
if (count < 0) { | |
done2 = true | |
break | |
} | |
off2 += count | |
} | |
if (off1 != off2 || done1 != done2) return false | |
for (i in 0 until off1) { | |
if (buf1[i] != buf2[i]) return false | |
} | |
} | |
true | |
} finally { | |
stream1.close() | |
stream2.close() | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment