Skip to content

Commit 4f4d4aa

Browse files
committed
stability: bound binary detail preview rendering
1 parent 24f3f6f commit 4f4d4aa

4 files changed

Lines changed: 61 additions & 8 deletions

File tree

app/src/main/java/com/kyhsgeekcode/disassembler/ui/tabs/BinaryDetailTab.kt

Lines changed: 28 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -20,20 +20,45 @@ import com.kyhsgeekcode.disassembler.R
2020
import com.kyhsgeekcode.disassembler.exporting.buildBinaryDetailsExportFileName
2121
import com.kyhsgeekcode.disassembler.exporting.writeTextDocument
2222
import com.kyhsgeekcode.disassembler.files.AbstractFile
23+
import kotlinx.coroutines.Dispatchers
2324
import kotlinx.coroutines.launch
25+
import kotlinx.coroutines.withContext
26+
27+
private const val MAX_RENDERED_BINARY_DETAILS_CHARS = 48_000
28+
private const val BINARY_DETAILS_TRUNCATION_NOTICE =
29+
"\n\n[Preview truncated. Use Save details to export the full text.]"
30+
31+
data class BinaryDetailsPreview(
32+
val text: String,
33+
val isTruncated: Boolean
34+
)
35+
36+
fun buildBinaryDetailsPreview(
37+
fullText: String,
38+
maxChars: Int = MAX_RENDERED_BINARY_DETAILS_CHARS
39+
): BinaryDetailsPreview {
40+
if (fullText.length <= maxChars) {
41+
return BinaryDetailsPreview(text = fullText, isTruncated = false)
42+
}
43+
return BinaryDetailsPreview(
44+
text = fullText.take(maxChars) + BINARY_DETAILS_TRUNCATION_NOTICE,
45+
isTruncated = true
46+
)
47+
}
2448

2549
@Composable
2650
fun BinaryDetailTabContent(data: AbstractFile) {
2751
val context = LocalContext.current
28-
val detailsText = remember(data) { data.toString() }
52+
val detailsPreview = remember(data) { buildBinaryDetailsPreview(data.toString()) }
2953
val scope = androidx.compose.runtime.rememberCoroutineScope()
3054
val exportDetailsLauncher = rememberLauncherForActivityResult(
3155
ActivityResultContracts.CreateDocument("text/plain")
3256
) { destinationUri ->
3357
if (destinationUri != null) {
3458
scope.launch {
3559
runCatching {
36-
writeTextDocument(context.contentResolver, destinationUri, detailsText)
60+
val fullText = withContext(Dispatchers.Default) { data.toString() }
61+
writeTextDocument(context.contentResolver, destinationUri, fullText)
3762
}.onSuccess {
3863
Toast.makeText(
3964
context,
@@ -65,7 +90,7 @@ fun BinaryDetailTabContent(data: AbstractFile) {
6590
Text(text = stringResource(id = R.string.save_details_to_file))
6691
}
6792
Text(
68-
text = detailsText,
93+
text = detailsPreview.text,
6994
modifier = Modifier
7095
.fillMaxSize()
7196
.verticalScroll(rememberScrollState())
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
package com.kyhsgeekcode.disassembler.ui.tabs
2+
3+
import kotlin.test.Test
4+
import kotlin.test.assertEquals
5+
import kotlin.test.assertFalse
6+
import kotlin.test.assertTrue
7+
8+
class BinaryDetailsPreviewTest {
9+
@Test
10+
fun `preview keeps short details unchanged`() {
11+
val preview = buildBinaryDetailsPreview("short text", maxChars = 32)
12+
13+
assertEquals("short text", preview.text)
14+
assertFalse(preview.isTruncated)
15+
}
16+
17+
@Test
18+
fun `preview truncates long details and adds notice`() {
19+
val preview = buildBinaryDetailsPreview("abcdefghijklmnopqrstuvwxyz", maxChars = 10)
20+
21+
assertTrue(preview.isTruncated)
22+
assertEquals(
23+
"abcdefghij\n\n[Preview truncated. Use Save details to export the full text.]",
24+
preview.text
25+
)
26+
}
27+
}

docs/maintenance/backlog-triage.ko.md

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77

88
| 항목 | 수량 | 판단 |
99
| --- | --- | --- |
10-
| 오픈 PR | 2 | 오래된 자동 bump PR과 `#728`에 흡수된 PR은 정리했다 |
10+
| 오픈 PR | 1 | 오래된 자동 bump PR과 `#728`에 흡수된 PR은 정리했고, `#726`도 현재 릴리스 워크플로에 superseded 되었다 |
1111
| 오픈 이슈 | 43 | 표면상 43개지만, 실제 작업 묶음은 대략 15~20개 수준으로 수렴한다 |
1212
| 즉시 닫기/대체 가능 후보 | 감소 | SWF 중복 이슈와 구형 Android 지원 이슈까지 포함해 일부 정리했다 |
1313
| 즉시 구현 후보 | 소수 | 릴리스 파이프라인, storage 정책 마감, crash 재현 클러스터가 우선이다 |
@@ -17,13 +17,12 @@
1717
| PR | 제목 | 제안 상태 | 판단 | 다음 액션 |
1818
| --- | --- | --- | --- | --- |
1919
| `#728` | Codex/maintenance baseline | 진행 중 | 현재 유지보수 기준선 PR이다 | 리뷰 반영 후 병합 기준으로 사용 |
20-
| `#726` | update deploy workflow | `planned-fast-follow` | 이슈 `#719`와 직접 연결되는 릴리스 워크플로 작업이다 | `master` 기준 최신 Gradle/Android 설정에 맞춰 재검토 |
2120

2221
## 최근 정리 완료
2322

2423
| 항목 | 처리 | 이유 |
2524
| --- | --- | --- |
26-
| PR `#723`, `#724`, `#725`, `#727` | 닫음 | `#728`에 흡수되었거나 유지보수 기준선 PR로 대체됨 |
25+
| PR `#723`, `#724`, `#725`, `#726`, `#727` | 닫음 | `#728`에 흡수되었거나 현재 release/preview workflow로 대체됨 |
2726
| PR `#704`, `#701`, `#699`, `#695`, `#693`, `#692`, `#677`, `#637`, `#615`, `#565` | 닫음 | 오래된 자동 bump/alpha 제안으로 현재 유지보수 기준선보다 뒤처짐 |
2827
| 이슈 `#112` | 닫음 | SWF 요청은 `#721`로 통합 |
2928
| 이슈 `#221` | 닫음 | 현재 유지보수 방향은 최신 Android 대응이며 Android 4.4 지원 복구는 범위 밖 |
@@ -34,7 +33,7 @@
3433
| --- | --- | --- | --- | --- |
3534
| 기준선 PR로 이미 다루는 이슈 | `#670`, `#396`, `#348` | `covered-by-open-pr` | 현재 `#728`에서 이미 수정됨 | `#728` 병합 후 정리 |
3635
| 최신 Android storage 정책 | `#95` | `planned-fast-follow` | 핵심 유지보수 항목이며 이미 SAF 전환을 시작했다 | 앱 전체 import/open 경로를 SAF 중심으로 계속 이관 |
37-
| 릴리스 산출물 부재 | `#719` | `planned-fast-follow` | 코드 문제보다 릴리스 파이프라인 문제다 | `#726`와 함께 릴리스 워크플로 정리 |
36+
| 릴리스 산출물 부재 | `#719` | `planned-fast-follow` | 코드 문제보다 릴리스 파이프라인 문제다 | CI artifact, preview prerelease, formal release 흐름으로 운영 정리 |
3837
| 대용량/메모리/RecyclerView 크래시 | `#219`, `#235`, `#442`, `#523` | `planned-fast-follow` | `#728`에서 큰 파일 byte cache 제한과 문자열 검색 결과 상한/stable key를 먼저 넣었다 | `#728` 병합 후 실제 150MB 파일과 긴 문자열 리스트로 재검증하고 나머지 OOM 경로를 분리 |
3938
| 회전/상태 복원 크래시 | `#160` | `covered-by-open-pr` | `#728`에서 Activity 재생성 시 외부 import intent 재처리를 막는 1차 가드를 넣었다 | `#728` 병합 후 실제 회전 회귀를 확인하고 정리 |
4039
| `.so`/ELF/autosetup | `#514`, `#543`, `#576`, `#137` | `covered-by-open-pr` | `#728`에서 64-bit ELF machine type 매핑과 override autosetup 재적용 경로를 먼저 수정했다 | `#728` 병합 후 실제 `.so` 샘플로 재검증하고 남는 parser 문제만 분리 |
@@ -51,7 +50,7 @@
5150
| 우선순위 | 항목 | 근거 |
5251
| --- | --- | --- |
5352
| 1 | `#728` 병합 가능 수준까지 정리 | 현재 기준선 PR이 병목이다 |
54-
| 2 | `#719` + `#726` 릴리스 파이프라인 정리 | 최신 빌드를 배포할 수 있어야 이슈 종료도 설득력이 생긴다 |
53+
| 2 | `#719` preview/release 운영 정리 | 최신 빌드를 배포할 수 있어야 이슈 종료도 설득력이 생긴다 |
5554
| 3 | `#95` storage 정책 마감 | 최신 Android 대응의 핵심이다 |
5655
| 4 | 메모리/회전 crash 클러스터 재현 | 오래된 crash report를 실질 작업 묶음으로 줄일 수 있다 |
5756
| 5 | 포맷 확장 요청 재정렬 | 실제 유지보수 범위와 별도 연구 과제를 나눠야 한다 |

docs/maintenance/implementation-log.ko.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@
3434
| 이슈 `#438` file chooser 정렬 크래시 | chooser 정렬을 pure helper로 분리하고 빈 라벨도 안전하게 정렬되도록 변경 | `it.text[0]` 직접 접근을 제거해서 빈/비정상 라벨이 섞인 경우에도 `Arrays.sort` 단계에서 죽지 않도록 만들고, 폴더 우선 정렬 규칙도 테스트로 고정했다 | `app/src/main/java/com/kyhsgeekcode/filechooser/NewFileChooserAdapter.kt`, `app/src/test/java/com/kyhsgeekcode/disassembler/FileChooserSortTest.kt` | 완료 |
3535
| 이슈 `#514`, `#543`, `#576` `.so`/ELF 아키텍처와 override autosetup | `x86_64`, `PPC64` ELF machine type을 64-bit disassembly mode로 매핑하고, binary overview에서 수동 설정을 적용하면 disassembly handle을 다시 열도록 바꿨다 | 일부 `.so`가 32-bit mode로 잘못 열리던 경로를 줄이고, `Override autosetup`이 값만 바꾸고 실제 disassembly는 안 바뀌던 문제를 수정했다 | `app/src/main/java/com/kyhsgeekcode/disassembler/models/Architecture.kt`, `app/src/main/java/com/kyhsgeekcode/disassembler/ui/tabs/BinaryOverviewTab.kt`, `app/src/main/java/com/kyhsgeekcode/disassembler/ui/tabs/BinaryTab.kt`, `app/src/test/java/com/kyhsgeekcode/disassembler/models/ArchitectureTest.kt`, `app/src/test/java/com/kyhsgeekcode/disassembler/ui/tabs/BinaryManualSetupConfigTest.kt` | 완료 |
3636
| 이슈 `#123`, `#720` 프로젝트 export와 details 저장 부재 | ZIP 생성기를 재귀 상대경로 방식으로 고치고, 프로젝트 overview에 SAF `CreateDocument` 기반 `Export project` 버튼을 추가했으며, binary detail 탭에는 `Save Details to file` 버튼을 구현했다 | 깨져 있던 project ZIP export 경로를 실제로 복구하고, 최신 Android 저장소 모델에 맞게 상세 정보 텍스트를 `.txt` 문서로 저장할 수 있게 했다 | `app/src/main/java/com/kyhsgeekcode/Util.kt`, `app/src/main/java/com/kyhsgeekcode/disassembler/exporting/ExportDocuments.kt`, `app/src/main/java/com/kyhsgeekcode/disassembler/project/ProjectManager.kt`, `app/src/main/java/com/kyhsgeekcode/disassembler/viewmodel/MainViewModel.kt`, `app/src/main/java/com/kyhsgeekcode/disassembler/ui/MainTab.kt`, `app/src/main/java/com/kyhsgeekcode/disassembler/ui/tabs/BinaryDetailTab.kt`, `app/src/test/java/com/kyhsgeekcode/disassembler/ProjectExportArchiveTest.kt`, `app/src/test/java/com/kyhsgeekcode/disassembler/exporting/BinaryDetailsExportTest.kt` | 완료 |
37+
| 이슈 `#219` 대용량 파일 detail 렌더링 OOM 완화 | binary detail 화면이 전체 문자열을 그대로 레이아웃하지 않도록 preview helper를 추가하고, 화면에는 잘린 preview만 유지하며 전체 내용은 export 시점에만 다시 생성하도록 바꿨다 | 큰 ELF/PE detail 문자열이 화면 레이아웃 단계에서 메모리를 과도하게 잡는 경로를 줄이고, 저장 기능은 유지한 채 UI 메모리 압박을 낮췄다 | `app/src/main/java/com/kyhsgeekcode/disassembler/ui/tabs/BinaryDetailTab.kt`, `app/src/test/java/com/kyhsgeekcode/disassembler/ui/tabs/BinaryDetailsPreviewTest.kt` | 완료 |
3738
| 이슈 `#129` `.ar` archive 지원 | 공용 archive extractor를 추가하고, Compose/legacy drawer의 archive 확장 경로를 ZIP 전용 구현에서 generic archive extractor로 교체했다 | archive 판정은 되는데 실제 확장은 ZIP만 되던 불일치를 제거해서 `.ar` 같은 지원 가능한 archive도 실제로 탐색 가능하게 만들었다 | `app/src/main/java/com/kyhsgeekcode/Util.kt`, `app/src/main/java/com/kyhsgeekcode/disassembler/ui/FileDrawerTree.kt`, `app/src/main/java/com/kyhsgeekcode/disassembler/FileDrawerListItem.kt`, `app/src/main/java/com/kyhsgeekcode/disassembler/FileDrawerListAdapter.kt`, `app/src/test/java/com/kyhsgeekcode/disassembler/ArchiveExtractionTest.kt` | 완료 |
3839
| 프로젝트 경로/파일명 회귀 방지 | 프로젝트 상대경로 계산과 import 파일명 정규화를 pure helper로 분리 | 단위 테스트가 가능하도록 로직을 분리하고 경계 케이스를 줄였다 | `app/src/main/java/com/kyhsgeekcode/disassembler/project/ProjectManager.kt`, `app/src/main/java/com/kyhsgeekcode/disassembler/viewmodel/MainViewModel.kt` | 완료 |
3940
| 회귀 테스트 부재 | `ProjectManager`, 저장소 권한, Hex 레이아웃, import 파일명 테스트 추가 | 최소한의 유지보수 안전망을 확보했다 | `app/src/test/java/com/kyhsgeekcode/disassembler/ProjectManagerTest.kt`, `app/src/test/java/com/kyhsgeekcode/disassembler/PermissionUtilsTest.kt`, `app/src/test/java/com/kyhsgeekcode/disassembler/ui/components/HexViewLayoutTest.kt`, `app/src/test/java/com/kyhsgeekcode/disassembler/viewmodel/ImportedFileNameTest.kt` | 완료 |
@@ -57,6 +58,7 @@
5758
| 강화된 `assembleDebugAndroidTest` | 통과 | Compose UI 기반 PR 회귀 테스트 세트가 instrumentation APK로 묶이는지 확인 |
5859
| large-file cache policy 테스트 | 통과 | 큰 파일은 메모리 캐시에 남기지 않는 규칙을 고정 |
5960
| string search accumulator 테스트 | 통과 | 문자열 결과 상한과 truncation 동작을 고정 |
61+
| binary detail preview 테스트 | 통과 | 긴 detail 문자열은 preview만 렌더링하고 notice를 붙이는 규칙을 고정 |
6062
| architecture mapping 테스트 | 통과 | `x86_64`, `PPC64`가 64-bit mode로 매핑되는 규칙을 고정 |
6163
| binary manual setup reload 테스트 | 통과 | override autosetup 변경 시 disassembly 재로드 필요 여부를 고정 |
6264
| project export archive 테스트 | 통과 | ZIP 엔트리가 절대경로를 포함하지 않고 `sourceFilePath`, `baseFolder/...`로 묶이는지 확인 |

0 commit comments

Comments
 (0)