처리중입니다. 잠시만 기다려주세요.
TTJ 코딩클래스
정규반 단과 자료실 테크 뉴스 코딩 퀴즈
테크 뉴스
Hacker News 2026.08.10 34
#AI

롬 패처 'slap'이 던지는 질문: 패치 포맷의 '스펙'은 어디까지인가

Hacker News 원문 보기

게임 롬을 수정해 배포하는 세계에서 '패치'는 오랜 관행이다. 원본 게임 파일에 번역, 버그 수정, 각종 개조 내용을 담은 별도의 패치 파일을 적용해 변형본을 만드는 방식인데, 제작자는 완성된 롬 자체가 아니라 원본에 적용할 '레시피'로서의 패치만 배포한다. 저작권 문제를 피하면서 결과물을 공유하는 사실상의 표준이다. 최근 공개된 slap은 바로 이 패치 적용 도구로, 스무 개에 달하는 포맷을 지원하는 다중 포맷 롬 패처를 표방한다. 제작자는 리눅스에서 쓸 만하고 자신의 FXPak 준비 작업에 잘 맞물리는 CLI 도구를 찾지 못해 직접 만들었다고 밝혔다. FOSS로 공개돼 있고 여러 플랫폼을 지원하며, 스크립트 친화적이면서도 구조화된 오류·경고·관찰 메시지를 풍부하게 내놓는 것이 특징이다.

slap의 기능은 네 가지로 정리된다. 패치와 원본 롬을 합쳐 수정본을 만드는 apply, 반대로 수정본에서 원본을 복원하는 undo, 한 포맷의 패치를 다른 포맷으로 바꾸는 convert, 그리고 패치가 무슨 일을 하는지 사람이 읽을 수 있게 풀어주는 explain이다. 구현 언어로 Haskell과 Rust를 함께 썼는데, 이 조합을 브라우저에서 매끄럽게 돌아가게 만드는 과정이 흥미로웠다고 제작자는 덧붙인다. 실제로 CLI 버전과 웹 버전이 모두 제공된다.

'적용은 관대하게, 생성은 보수적으로'

이 프로젝트에서 가장 곱씹어볼 대목은 성능 수치가 아니라 '포맷의 스펙이란 무엇인가'라는 질문이다. 현실에 존재할 법한 패치를 올바르게 적용하는 것은 당연한 전제다. 문제는 그 바깥 경계다. 예컨대 IPS 포맷에서 레코드가 서로 겹쳐도 되는가, 순서가 뒤죽박죽이어도 되는가. 둘 다 허용된다면 적용은 처음 보이는 것만큼 자명하지 않다. 또 입력 파일보다 큰 크기로 '잘라내라'는 절단 표시는 어떻게 존중해야 하는가. IPS는 16MiB 너머를 주소로 지정할 수 없지만, 경계 안에서 시작해 16MiB를 살짝 넘겨 쓰는 레코드는 기술할 수 있다. 논리적으로 일관되고 결과도 예측 가능하지만 대단히 기묘한 이런 패치를, 적용은 하되 생성까지 할 것인가는 별개의 문제다.

비슷한 고민이 포맷마다 이어진다. EBP는 JSON 메타데이터로 네 개의 문자열을 저장하는데, 실제 표현력은 그보다 훨씬 크다. 무한 중첩까지 허용된다고 봐야 하는지, 최소한 UTF-8이라고 가정해도 되는지가 애매하다. NINJA2에는 입력 롬을 정규형(디인터리브, 헤더 제거, N64라면 z64 바이트 순서 등)으로 맞추는 '정규화' 기능이 있는데, 패처가 지정된 정규화 절차를 모르면 적용을 거부한다. 그런데 이 포맷은 정규화된 입력의 체크섬을 저장하므로, 제작자는 포기하기 전에 입력이 이미 기대한 형태인지 확인하는 편이 낫다고 본다. 다만 이것이 표준을 넘어서는 '포용·확장·소멸' 전략은 아닌지 스스로 경계한다.

BPS는 아직 아무것도 기록되지 않은 출력의 다른 부분에서 내용을 복사하는 동작을 허용하는 듯 보이고, PPF3는 파일 크기를 추적하지 않으면서 undo를 지원해 크기 변경과 되돌리기가 논리적으로 충돌한다. 원본 도구는 크기 변경을 막으려 한 것으로 보이지만 실제로는 제대로 작동하지 않은 것 같다고 한다. slap이 택한 원칙은 명료하다. 생성할 때는 어떤 도구든 무리 없이 적용할 수 있는 결과만 내보내는 보수적 태도를, 적용할 때는 각 포맷의 표현 범위 전체를 지원하는 관대한 태도를 취한다. 그 '선'이 어디인지 찾아내는 것이 개발의 핵심이었다.

인코딩과 오류 진단, 그리고 벤치마크의 함정

텍스트 메타데이터 처리도 눈여겨볼 만하다. 제작자는 여러 포맷이 ASCII 전용일 것이라 예상했지만 실제로는 그렇지 않았다고 한다. slap은 UTF-8로 출력하며, 포맷 규칙이 'UTF-8을 쓰라'이거나 '시스템 코드페이지를 쓰라'인 경우가 많은데 현대 시스템에서는 후자도 UTF-8이므로 문제가 없다는 판단이다. 읽기·표시 단계는 더 까다롭다. 일부 포맷은 임의의 텍스트가 아니라 임의의 바이너리 데이터 필드를 두는데, slap은 이를 표시하되 실행하지는 않는 원칙을 지킨다. 출력 불가능한 코드포인트는 실제 제어문자를 실행하는 대신 처럼 이스케이프해 보여주고, 해독 불가능한 바이트열은 U+FFFD로 바꾸며 위치를 알리는 경고를 남긴다. 의심스러운 임베디드 데이터에서 제어문자가 그대로 실행되는 상황을 막기 위한 방어다. 무엇이 어디서 잘못됐는지 이름을 붙여 알려주는 데 상당한 공을 들였고, 관심 있는 사람은 Error.hs, ApplyError.hs, VCDIFF.hs를 보라고 안내한다.

제작자는 성능 표도 함께 공개했지만, 그 수치를 읽는 방식에 대해 이례적일 만큼 솔직하다. CLI 표의 모든 숫자에는 프로세스 시작 비용이 포함돼 있어, 가장 작은 4MiB급 경쟁은 패칭이 아니라 10~25ms의 실행·구동 바닥값이 승부를 가른다. javaxdelta는 매 호출마다 JVM을 띄우느라 작은 파일에서 손해를 보지만 라이브러리 자체는 빠르며, 그 비용은 520MiB에서는 잡음 수준으로 사라진다. applyppf3나 ninja 계열 적용기는 새 파일을 쓰는 대신 파일을 제자리에서 수정하기 때문에, 전체 출력을 새로 쓰는 slap과는 애초에 '다른 작업'을 같은 표에 올려놓은 셈이라고 명시한다. 웹 버전은 커뮤니티 표준인 RomPatcher.js와 비교되는데, 4MiB에서는 양쪽 모두 정밀한 탐색을 수행해 slap이 15초 이상 걸리는 대신 작은 패치를 만들고, 4MiB를 넘으면 RomPatcher.js가 선형 방식으로 전환해 빨라지는 대신 더 큰 패치를 낸다는 트레이드오프가 드러난다.

실무자 입장에서 slap이 주는 교훈은 단순한 '또 하나의 도구'를 넘어선다. 오래되고 느슨하게 정의된 파일 포맷을 다룰 때, '스펙에 맞다'는 판단이 생각보다 훨씬 모호하며 생성과 적용이라는 두 방향에서 서로 다른 기준이 필요하다는 점이다. 겹치거나 비단조적인 레코드, 경계를 넘나드는 쓰기, 크기 변경과 되돌리기의 충돌 같은 사례는 롬 패칭에만 국한되지 않고 파서나 데이터 교환 포맷을 다루는 모든 개발 현장에 그대로 적용된다. 다만 이 도구가 지원하는 스무 개 포맷과 그 경계 판단은 어디까지나 제작자 한 명의 해석에 기댄 것이어서, 실제 업무에 도입한다면 자신이 쓰는 포맷에서 slap의 관대함이 원본 도구와 정확히 어긋나지 않는지 직접 검증하는 절차가 필요하다.

이 뉴스가 유용했나요?

이 기술을 직접 배워보세요

AI 도구, 직접 활용해보세요

AI 시대, 코딩으로 수익을 만드는 방법을 배울 수 있습니다.

AI 활용 강의 보기

"비전공 직장인인데 반년 만에 수익 파이프라인을 여러 개 만들었습니다"

실제 수강생 후기
  • 비전공자도 6개월이면 첫 수익
  • 20년 경력 개발자 직강
  • 자동화 프로그램 + 소스코드 제공

매일 AI·개발 뉴스를 받아보세요

주요 테크 뉴스를 매일 아침 이메일로 전해드립니다.

스팸 없이, 언제든 구독 취소 가능합니다.