[cpp] UTF-8 INI 파일 다루기

@codemaru · June 01, 2016 · 6 min read

A/W 함수

윈도우 API는 문자열을 다루는 경우에 크게 두 종류의 함수를 제공한다. A/W 함수가 그것이다. A 함수는 멀티바이트로 문자열을 처리하는 함수를 의미하고, W 함수는 UTF-16 방식으로 문자열을 처리하는 함수를 의미한다. A 함수는 파라미터 타입으로 char를 W 함수는 wchar_t를 사용하기 때문에 크게 헷갈릴 일도 없고 직관적이다.

윈도우는 기본적으로 제공하는 ini 파일 조작 API 관련해서 아래와 같이 이런 두 종류의 API를 제공하고 있다.

WINBASEAPI
DWORD
WINAPI
GetPrivateProfileStringA(
    __in_opt LPCSTR lpAppName,
    __in_opt LPCSTR lpKeyName,
    __in_opt LPCSTR lpDefault,
    __out_ecount_part_opt(nSize, return + 1) LPSTR lpReturnedString,
    __in     DWORD nSize,
    __in_opt LPCSTR lpFileName
    );

WINBASEAPI
DWORD
WINAPI
GetPrivateProfileStringW(
    __in_opt LPCWSTR lpAppName,
    __in_opt LPCWSTR lpKeyName,
    __in_opt LPCWSTR lpDefault,
    __out_ecount_part_opt(nSize, return + 1) LPWSTR lpReturnedString,
    __in     DWORD nSize,
    __in_opt LPCWSTR lpFileName
    );

그렇다면 ini 파일의 포맷은?

GetPrivateProfileStringA 함수를 사용하면 멀티바이트 형태로 내가 원하는 값들을 지정하고 거기에 해당하는 결과 값을 멀티바이트 형태로 받을 수 있다. 반대로 GetPrivateProfileStringW 함수를 사용하면 UTF-16 형태로 지정하고 결과를 받을 수 있다. 여기까지만 생각하면 심플하고 복잡할 것도 없지만 조금만 더 호기심을 가져보면 뭔가 애매모호한 것들이 많다. 바로 파일의 형태다.

lpFileName으로 지정하는 파일은 어떤 형태여야 할까? 어떤 코드페이지로 작성된 멀티바이트 ini 파일도 딱딱 맞춰서 읽을 수 있을까? UTF-8 UTF-16 등으로 작성된 유니코드 파일도 마법처럼 인식해줄까? 아니면 A 함수는 멀티바이트 ini 파일에만 써야 하고 W 함수는 UTF-16 ini 파일에만 써야 할까? 등등의 무수히 많은 질문이 올 수 있다.

아마 대부분의 프로그래머가 해당 API를 사용하면서 그런 의문을 품지는 않았을 것 같다. 왜냐하면 대충 쓰면 적당히 동작하기 때문이다. 그래서 그런지 MSDN에도 lpFileName으로 지정할 수 있는 파일의 형태에 대해서는 어떠한 언급도 없다. 하지만 컴퓨터의 세계에서 적당히 대충은 항상 문제를 일으킨다. 그래서 조금 깊이 있게 살펴보자.

윈도우에서 제공하는 ini 파일을 다루는 API는 딱 두 종류의 파일에 대해서만 처리할 수 있도록 설계되어 있다. 하나는 시스템 코드페이지로 작성된 멀티바이트(ANSI) ini 파일이고, 다른 하나는 UTF-16으로 작성된 ini 파일이다. 이는 A/W 함수에 상관 없이 사용된다. ini API 내부적으로 파일을 열 때에 RtlIsTextUnicode를 사용해서 파일에서 읽은 내용이 UTF-16인지 아닌지를 판별한다. UTF-16인 경우에 A 함수를 호출하면 파라미터를 RtlAnsiStringToUnicodeString 함수를 사용해서 변환해서 사용하고, 멀티바이트 파일이 인 경우에 W 함수를 호출하면 반대로 RtlUnicodeStringToAnsiString 함수를 사용해서 파라미터를 내부적으로 변환한다.

UTF-8 ini 파일을 다루는 방법

그렇다면 윈도우 ini API를 사용해서 UTF-8 ini 파일을 다룰 수는 없는 것일까? 결과론적으론 그렇다. 왜냐하면 API 내부적으로 UTF-8 변환을 지원하지 않기 때문이다. 하지만 대체로 많은 경우에 섹션 이름이나, 키 이름 같은 경우는 영어를 사용하는 것이 관례이고, 키에 해당하는 값에만 ANSI 문자가 아닌 다른 문자가 포함되는 경우가 많다. 이렇게 한정된 조건을 가진 UTF-8 ini 파일의 경우에는 윈도우 ini API를 사용해서 조작하는 것이 가능하다.

사용하는 방법은 간단하다. W 함수를 사용하면 안 된다. 왜냐하면 내부적으로 UTF-8로 인코딩 된 것을 UTF-16으로 디코딩하려고 시도할 것이기 때문이다. 그러니 무조건 A 함수를 사용하고 받은 멀티바이트 결과 값을 MultiBytesToWideChar 등의 함수로 UTF-8을 디코딩해서 UTF-16 문자열로 처리하면 된다.

요약하면 저장할 때에는 유니코드 문자열을 UTF-8로 인코딩한 다음 ini A계열 함수를 사용해서 저장하면 되고, 읽을 때에는 ini A계열 함수를 사용해서 읽은 값을 UTF-8로 디코딩해서 유니코드 문자열로 변환해서 사용하면 반쪽짜리 UTF-8 ini 파일을 처리할 수 있다.

@codemaru
돌아보니 좋은 날도 있었고, 나쁜 날도 있었다. 그런 나의 모든 소소한 일상과 배움을 기록한다. 여기에 기록된 모든 내용은 한 개인의 관점이고 의견이다. 내가 속한 조직과는 1도 상관이 없다.
(C) 2001 YoungJin Shin, 0일째 운영 중