RFC 30: 유니코드 파일명

저자: 프랑크 바르메르담

연락처: warmerdam@pobox.com

상태: 승인

요약

이 문서는 GDAL/OGR에서 파일명을 일반적으로 UTF-8 문자열로 처리하는 단계를 설명합니다. 간단하게 요약하자면 GDAL/OGR 인터페이스에 전송되어 오는 그리고 GDAL/OGR 인터페이스가 반환하는 파일명을 UTF-8 인코딩으로 가정할 것입니다. 일부 운영 체제, 특히 윈도우 상에서는 저수준 VSI*L API에서 “확장 문자(wide character)” 인터페이스를 사용해야 할 것입니다.

주요 인터페이스

VSI*L API

VSI*L API에서는 모든 파일명을 UTF-8 인코딩으로 취급할 것입니다. 즉 확장 문자 인터페이스를 사용하기 위해 cpl_vsil_win32.cpp 의 상당 부분을 업데이트해야 할 것이라는 뜻입니다.

  • VSIFOpenL()

  • VSIFStatL()

  • VSIReadDir()

  • VSIMkdir()

  • VSIRmdir()

  • VSIUnlink()

  • VSIRename()

예전 (저용량 파일) VSI API

윈도우 상에서 UTF-8 파일명을 지원하기 위해 fopen() 대신 _wfopen()을 사용하도록 예전 VSIFOpen() 함수를 조정할 것입니다.

  • VSIFOpen()

  • VSIStat()

파일명 파싱

경로/확장자 구분자(delimiter) 문자 ‘.’, ‘’, ‘/’ 및 ‘:’은 UTF-8 문자열의 아스키가 아닌 부분에 절대 나타나지 않기 때문에 기존 경로 파싱 함수가 현재 그대로 작동하도록 놔두어도 안전합니다. 기존 경로 파싱 함수가 UTF-8 경로에 있는 특수 문자에 대한 실제 문자 범위를 알아야 할 필요가 없습니다. 다음 함수들은 변경하지 않을 것입니다.

  • CPLGetPath()

  • CPLGetDirname()

  • CPLGetFilename()

  • CPLGetBasename()

  • CPLGetExtension()

  • CPLResetExtension()

기타

  • CPLStat()

  • CPLGetCurrentDir()

  • GDALDataset::GetFileList()

이 함수들도 파일명을 UTF-8 인코딩으로 취급해야 할 것입니다.

윈도우

현재 윈도우의 cpl_vsil_win32.cpp 모듈은 CreateFile() 을 아스키 파일명으로 사용합니다. stat(), rename, mkdir 등등에 대해 CreateFileW() 및 다른 확장 문자 함수를 사용하도록 변환해야 합니다. 이미 구현 프로토타입을 개발(r20620)했습니다.

리눅스 / 유닉스 / macOS

현대 리눅스, 유닉스 및 macOS 운영 체제 상에서 fopen(), stat(), readdir() 함수는 이미 UTF-8 문자열을 지원합니다. 현재 리눅스/유닉스/macOS 상에 어떤 작업도 필요하지 않을 것이라고 예상되긴 하지만 확실한 것은 아닙니다. 이 RFC의 정의에 따라 구식 운영 체제 및 하위 표준 운영 체제(WinCE?)의 경우 UTF-8 파일명이 아닌 아스키 파일명만 지원하도록 허용해도 된다고 간주합니다.

메타데이터

다양한 위치에서 일반 텍스트가 파일명을 담고 있을 수도 있습니다. 한 가지 당연한 예를 들자면 SUBDATASET 도메인으로부터 반환되는 하위 데이터셋 파일명입니다. 예전에는 이 파일명을 그냥 평문 텍스트로 노출시켰고, 문자 집합의 해석을 정의하지 않았습니다. 이 RFC의 일환으로 이런 파일명도 UTF-8 포맷으로 되어 있다고 간주해야 한다고 선언합니다.

파이썬 변경 사항

파이썬 2.6버전의 경우 gdal.Open() 같은 함수들이 유니코드 문자열은 받아들이지 않지만, UTF-8 문자열 객체는 받아들이는 것으로 관찰됩니다. 가능한 해결책 한 가지는 몇몇 선별적인 위치에서 바인딩을 업데이트해서 전송되어 오는 유니코드 문자열을 식별할 수 있게 하고, 유니코드 문자열을 UTF-8 문자열로 변환하게 하는 것입니다. 다음은 그 예시입니다:

filename =  u'xx\u4E2D\u6587.\u4E2D\u6587'
if type(filename) == type(u'a'):
    filename = filename.encode('utf-8')

바인딩에서 이를 가장 쉽게 달성할 수 있는 방법은 불확실합니다. 주요 항목들은 다음과 같습니다:

  • gdal.Open()

  • ogr.Open()

  • gdal.ReadDir()

  • gdal.PushFinderLocation()

  • gdal.FindFile()

  • gdal.Unlink()

마찬가지로 파일명을 반환하는 (gdal.ReadDir() 같은) 모든 인터페이스는 이후 문자열 객체가 아니라 유니코드 객체를 반환할 것입니다.

Python 3.x 이후 버전의 문자열은 항상 유니코드라는 사실도 기억하십시오.

C# 변경 사항

C#에서 일반적으로 유니코드 C# 문자열을 PtrToStringAnsi 감독자를 가진 C 문자열로 변환한다고 세케레시 터마시가 언급했습니다. 아마도 파일명으로 간주되는 모든 인터페이스 문자열에 대해 UTF-8 변환기를 사용해야 할 것입니다. 마찬가지로 UTF-8 인코딩으로 취급하도록 의도된 OGR 문자열 속성값에도 이를 적용해야 할 것입니다.

(원저자(프랑크 바르메르담)가 C# 바인딩 전문이 아니기 때문에, 누가 이런 측면을 처리할 것인지는 불명확합니다.)

펄(Perl) 변경 사항

펄에서의 일반 규칙은 펄에 전송하기 전에 모든 문자열을 디코딩하고 문자열을 산출할 때 인코딩해야 한다는 것입니다. 실제 상황에서는 보통 그냥 작동합니다. 확실하게 하기 위해, 아리 욜마(Ari Jolma)가 UTF-8로부터 FindFile 및 ReadDir로 명확하게 디코딩하도록 추가(#20800)했습니다.

자바 변경 사항

자바의 경우 변경할 필요가 없습니다. 자바 문자열은 유니코드이며 자바 SWIG 바인딩에서 이미 UTF-8로 변환됩니다. 다시 말해 자바 바인딩은 이미 GDAL/OGR에서 UTF-8 문자열을 전송하고 전송받는다고 가정한다는 의미입니다.

명령줄 문제점

윈도우 상에서는 일반적으로 main()으로 전송되는 ‘argv[]’가 로케일 문자 집합에서 표현할 수 없는 특수 문자를 사용하는 파일명을 표현할 수 없을 것입니다. (UTF-8로 쉽게 변환되는) UCS-16 파일명을 수집할 수 있는 GetCommandLineW() 및 CommandLinetoArgvW() 함수를 이용해서 명령줄을 가져와 확장 문자로 파싱할 수도 있습니다. 하지만 이렇게 하면 윈도우 상에서 setargv.obj 를 사용해서 와일드카드 문자를 확장하는 것을 방해하게 됩니다.

아직도 훌륭한 해결책이 떠오르지 않기 때문에, 지금으로서는 GDAL/OGR 명령줄 유틸리티가 특수 문자를 사용하는 파일명을 전송할 수 있게 해주는 어떤 변경 사항도 적용할 예정이 없습니다. 따라서 이 RFC의 주된 목적은 GDAL/OGR를 사용하는 다른 응용 프로그램들이 특수 문자를 사용하는 파일명을 활용할 수 있도록 보장하는 것입니다.

파일 포맷

이 제안을 구현하는 것은 실제로는 VSIFOpenL(), VSIFOpen() 및 관련 함수들을 사용하는 파일 포맷 드라이버들에만 국한됩니다. 외부 라이브러리에 의존하는 (예: NetCDF) 일부 드라이버들은 파일 I/O API와 연결할 수 있는 방법이 없기 때문에 UTF-8 파일명을 지원하지 못 할 수도 있습니다. 이런 드라이버들을 구별할 수 있다면 좋을 것 같습니다.

적어도 GDAL_DCAP_VIRTUALIO 메타데이터 항목이 YES로 설정된 모든 드라이버는 UTF-8을 지원할 것입니다. 아마도 이번 기회에 이 드라이버 메타데이터를 좀 더 균등하게 적용해야 할 것입니다. (완료)

테스트 스위트

테스트 스위트에 멀티바이트 UTF-8 파일명을 테스트할 수 있는 몇몇 테스트를 추가해야 할 것입니다. VSI*L API의 이런 측면을 지원하기 위해, 파이썬에 특히 rename, mkdir, rmdir 함수들 및 VSIFOpenL 자체를 노출시켰습니다.

문서화

적절한 API 진입점(entry point)을 UTF-8 문자열을 가져오고 반환하는 것으로 문서화할 것입니다.

구현

현재 구현 중이며 #3766 티켓에서 추적하고 있습니다.