Skip to content

Commit ab80976

Browse files
committed
handle renaming zip entries properly
1 parent cca4905 commit ab80976

File tree

9 files changed

+195
-25
lines changed

9 files changed

+195
-25
lines changed

app/src/main/java/com/raival/compose/file/explorer/screen/main/tab/files/task/CompressTask.kt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -131,6 +131,7 @@ class CompressTask(
131131
append(content.content.displayName)
132132
append(" -> ")
133133
append(content.status.name)
134+
append("\n")
134135
}
135136
}
136137
}

app/src/main/java/com/raival/compose/file/explorer/screen/main/tab/files/task/CopyTask.kt

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -216,7 +216,8 @@ class CopyTask(
216216
pendingFiles.forEach { content ->
217217
append(content.content.displayName)
218218
append(" -> ")
219-
appendLine(content.status.name)
219+
append(content.status.name)
220+
append("\n")
220221
}
221222
}
222223
}

app/src/main/java/com/raival/compose/file/explorer/screen/main/tab/files/task/DeleteTask.kt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -152,6 +152,7 @@ class DeleteTask(
152152
append(content.source.displayName)
153153
append(" -> ")
154154
append(content.status.name)
155+
append("\n")
155156
}
156157
}
157158
}

app/src/main/java/com/raival/compose/file/explorer/screen/main/tab/files/task/RenameTask.kt

Lines changed: 181 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -10,11 +10,15 @@ import com.raival.compose.file.explorer.screen.main.tab.files.holder.LocalFileHo
1010
import com.raival.compose.file.explorer.screen.main.tab.files.holder.ZipFileHolder
1111
import com.raival.compose.file.explorer.screen.main.tab.files.misc.FileMimeType.apkFileType
1212
import com.reandroid.archive.ZipAlign
13-
import net.lingala.zip4j.ZipFile
1413
import java.io.File
14+
import java.io.FileOutputStream
15+
import java.io.IOException
1516
import java.text.SimpleDateFormat
1617
import java.util.Date
1718
import java.util.Locale
19+
import java.util.zip.ZipEntry
20+
import java.util.zip.ZipFile
21+
import java.util.zip.ZipOutputStream
1822

1923
class RenameTask(val sourceContent: List<ContentHolder>) : Task() {
2024
private var parameters: RenameTaskParameters? = null
@@ -111,6 +115,54 @@ class RenameTask(val sourceContent: List<ContentHolder>) : Task() {
111115
processName = globalClass.getString(R.string.renaming)
112116
}
113117

118+
// Check if we're dealing with zip files and handle them separately
119+
val firstPendingItem = pendingContent.firstOrNull { it.status == TaskContentStatus.PENDING }
120+
if (firstPendingItem?.source is ZipFileHolder) {
121+
try {
122+
handleZipFileRenaming()
123+
} catch (e: Exception) {
124+
logger.logError(e)
125+
markAsFailed(
126+
globalClass.resources.getString(
127+
R.string.task_summary_failed,
128+
e.message ?: emptyString
129+
)
130+
)
131+
return
132+
}
133+
} else {
134+
// Handle local files
135+
handleLocalFileRenaming()
136+
}
137+
138+
if (progressMonitor.status == TaskStatus.RUNNING) {
139+
val sample = sourceContent.first()
140+
if (sample is ZipFileHolder) {
141+
if (sample.zipTree.source.extension == apkFileType) {
142+
progressMonitor.apply {
143+
processName = globalClass.resources.getString(R.string.aligning_apk)
144+
progress = -1f
145+
contentName = emptyString
146+
}
147+
ZipAlign.alignApk(sample.zipTree.source.file)
148+
}
149+
}
150+
}
151+
152+
if (progressMonitor.status == TaskStatus.RUNNING) {
153+
progressMonitor.status = TaskStatus.SUCCESS
154+
progressMonitor.summary = buildString {
155+
pendingContent.forEach { content ->
156+
append(content.source.displayName)
157+
append(" -> ")
158+
append(content.status.name)
159+
append("\n")
160+
}
161+
}
162+
}
163+
}
164+
165+
private suspend fun handleLocalFileRenaming() {
114166
pendingContent.forEachIndexed { index, itemToRename ->
115167
if (aborted) {
116168
progressMonitor.status = TaskStatus.PAUSED
@@ -127,13 +179,8 @@ class RenameTask(val sourceContent: List<ContentHolder>) : Task() {
127179
try {
128180
if (itemToRename.source is LocalFileHolder) {
129181
itemToRename.source.file.renameTo(File(itemToRename.newPath))
130-
} else if (itemToRename.source is ZipFileHolder) {
131-
ZipFile(itemToRename.source.zipTree.source.file).renameFile(
132-
itemToRename.source.uniquePath + if (itemToRename.source.isFolder) "/" else emptyString,
133-
itemToRename.newPath
134-
)
182+
itemToRename.status = TaskContentStatus.SUCCESS
135183
}
136-
itemToRename.status = TaskContentStatus.SUCCESS
137184
} catch (e: Exception) {
138185
logger.logError(e)
139186
markAsFailed(
@@ -146,30 +193,140 @@ class RenameTask(val sourceContent: List<ContentHolder>) : Task() {
146193
}
147194
}
148195
}
196+
}
149197

150-
if (progressMonitor.status == TaskStatus.RUNNING) {
151-
val sample = sourceContent.first()
152-
if (sample is ZipFileHolder) {
153-
if (sample.zipTree.source.extension == apkFileType) {
154-
progressMonitor.apply {
155-
processName = globalClass.resources.getString(R.string.aligning_apk)
156-
progress = -1f
157-
contentName = emptyString
198+
private suspend fun handleZipFileRenaming() {
199+
val zipFileHolder = pendingContent.first().source as ZipFileHolder
200+
val sourceZipFile = zipFileHolder.zipTree.source.file
201+
val tempFile = File(sourceZipFile.parent, "${sourceZipFile.nameWithoutExtension}_temp.zip")
202+
203+
try {
204+
// Create a map of old paths to new paths for all items to rename
205+
val renameMap = mutableMapOf<String, String>()
206+
val foldersToRename = mutableSetOf<String>()
207+
208+
pendingContent.filter { it.status == TaskContentStatus.PENDING }.forEach { item ->
209+
val zipHolder = item.source as ZipFileHolder
210+
val oldPath = zipHolder.uniquePath
211+
val newPath = item.newPath
212+
213+
if (zipHolder.isFolder) {
214+
foldersToRename.add(oldPath)
215+
}
216+
217+
renameMap[oldPath] = newPath
218+
}
219+
220+
// Open the source zip file for reading
221+
ZipFile(sourceZipFile).use { sourceZip ->
222+
// Create a new zip file
223+
ZipOutputStream(FileOutputStream(tempFile)).use { zipOut ->
224+
225+
val entries = sourceZip.entries().toList()
226+
var processedCount = 0
227+
228+
entries.forEach { entry ->
229+
if (aborted) {
230+
progressMonitor.status = TaskStatus.PAUSED
231+
return
232+
}
233+
234+
val entryName = entry.name.removeSuffix("/")
235+
var newEntryName = entryName
236+
var shouldRename = false
237+
238+
// Check direct rename
239+
if (renameMap.containsKey(entryName)) {
240+
newEntryName = renameMap[entryName]!!
241+
shouldRename = true
242+
} else {
243+
// Check if this entry is inside a folder being renamed
244+
for (folderPath in foldersToRename) {
245+
if (entryName.startsWith("$folderPath/")) {
246+
val relativePath = entryName.substring(folderPath.length + 1)
247+
newEntryName = "${renameMap[folderPath]}/$relativePath"
248+
shouldRename = true
249+
break
250+
}
251+
}
252+
}
253+
254+
// Restore trailing slash for directories
255+
if (entry.isDirectory) {
256+
newEntryName += "/"
257+
}
258+
259+
// Create new entry with the new name
260+
val newEntry = ZipEntry(newEntryName).apply {
261+
time = entry.time
262+
if (!entry.isDirectory) {
263+
method = entry.method
264+
if (entry.method == ZipEntry.STORED) {
265+
size = entry.size
266+
crc = entry.crc
267+
}
268+
}
269+
}
270+
271+
zipOut.putNextEntry(newEntry)
272+
273+
// Copy entry data if it's not a directory
274+
if (!entry.isDirectory) {
275+
sourceZip.getInputStream(entry).use { inputStream ->
276+
inputStream.copyTo(zipOut)
277+
}
278+
}
279+
280+
zipOut.closeEntry()
281+
282+
// Update progress
283+
processedCount++
284+
progressMonitor.apply {
285+
contentName = entry.name
286+
progress = processedCount.toFloat() / entries.size
287+
}
288+
289+
// Mark corresponding pending items as successful
290+
if (shouldRename) {
291+
pendingContent.find {
292+
(it.source as ZipFileHolder).uniquePath == entryName
293+
}?.status = TaskContentStatus.SUCCESS
294+
}
158295
}
159-
ZipAlign.alignApk(sample.zipTree.source.file)
160296
}
161297
}
162-
}
163298

164-
if (progressMonitor.status == TaskStatus.RUNNING) {
165-
progressMonitor.status = TaskStatus.SUCCESS
166-
progressMonitor.summary = buildString {
167-
pendingContent.forEach { content ->
168-
append(content.source.displayName)
169-
append(" -> ")
170-
append(content.status.name)
299+
// Replace the original file with the new one
300+
if (sourceZipFile.delete()) {
301+
if (!tempFile.renameTo(sourceZipFile)) {
302+
throw IOException(globalClass.getString(R.string.failed_to_replace_original_zip_file))
171303
}
304+
} else {
305+
throw IOException(globalClass.getString(R.string.failed_to_delete_original_zip_file))
306+
}
307+
308+
// Mark any remaining pending items as successful (for folders without zip entries)
309+
pendingContent.filter { it.status == TaskContentStatus.PENDING }.forEach { item ->
310+
val zipHolder = item.source as ZipFileHolder
311+
if (zipHolder.isFolder) {
312+
// Check if this folder has any children that were successfully renamed
313+
val hasRenamedChildren = pendingContent.any { other ->
314+
other.status == TaskContentStatus.SUCCESS &&
315+
(other.source as ZipFileHolder).uniquePath.startsWith("${zipHolder.uniquePath}/")
316+
}
317+
318+
if (hasRenamedChildren) {
319+
item.status = TaskContentStatus.SUCCESS
320+
}
321+
}
322+
}
323+
324+
} catch (e: Exception) {
325+
// Clean up temp file if it exists
326+
if (tempFile.exists()) {
327+
tempFile.delete()
172328
}
329+
throw e
173330
}
174331
}
175332

app/src/main/res/values-fa/strings.xml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -372,4 +372,6 @@
372372
<string name="aligning_apk">در حال هم‌ترازی فایل APK</string>
373373
<string name="invalid_apk_file">فایل APK نامعتبر</string>
374374
<string name="some_files_are_moved_into_their_subdirectories_those_will_be_excluded">برخی از فایل‌ها به زیرشاخه‌های خود منتقل می‌شوند، آنها مستثنی خواهند شد.</string>
375+
<string name="failed_to_replace_original_zip_file">ناموفق در جایگزینی فایل zip اصلی</string>
376+
<string name="failed_to_delete_original_zip_file">ناموفق در حذف فایل zip اصلی</string>
375377
</resources>

app/src/main/res/values-pt-rBR/strings.xml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -372,4 +372,6 @@
372372
<string name="aligning_apk">Alinhando o arquivo APK</string>
373373
<string name="invalid_apk_file">Arquivo APK inválido</string>
374374
<string name="some_files_are_moved_into_their_subdirectories_those_will_be_excluded">Alguns arquivos são movidos para seus subdiretórios, eles serão excluídos.</string>
375+
<string name="failed_to_replace_original_zip_file">Falha ao substituir o arquivo zip original</string>
376+
<string name="failed_to_delete_original_zip_file">Falha ao excluir o arquivo zip original</string>
375377
</resources>

app/src/main/res/values-ru/strings.xml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -372,4 +372,6 @@
372372
<string name="aligning_apk">Выравнивание файла APK</string>
373373
<string name="invalid_apk_file">Неверный файл APK</string>
374374
<string name="some_files_are_moved_into_their_subdirectories_those_will_be_excluded">Некоторые файлы перемещены в их подкаталоги, они будут исключены.</string>
375+
<string name="failed_to_replace_original_zip_file">Не удалось заменить исходный zip-файл</string>
376+
<string name="failed_to_delete_original_zip_file">Не удалось удалить исходный zip-файл</string>
375377
</resources>

app/src/main/res/values-zh/strings.xml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -372,4 +372,6 @@
372372
<string name="aligning_apk">对齐APK文件</string>
373373
<string name="invalid_apk_file">无效的APK文件</string>
374374
<string name="some_files_are_moved_into_their_subdirectories_those_will_be_excluded">一些文件被移动到它们的子目录中,这些文件将被排除。</string>
375+
<string name="failed_to_replace_original_zip_file">替换原始zip文件失败</string>
376+
<string name="failed_to_delete_original_zip_file">删除原始zip文件失败</string>
375377
</resources>

app/src/main/res/values/strings.xml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -373,4 +373,6 @@
373373
<string name="aligning_apk">Aligning APK file</string>
374374
<string name="invalid_apk_file">Invalid APK</string>
375375
<string name="some_files_are_moved_into_their_subdirectories_those_will_be_excluded">Some files are moved into their subdirectories, those will be excluded.</string>
376+
<string name="failed_to_replace_original_zip_file">Failed to replace original zip file</string>
377+
<string name="failed_to_delete_original_zip_file">Failed to delete original zip file</string>
376378
</resources>

0 commit comments

Comments
 (0)