zlib — 압축과 해제 연산

zlib — 압축과 해제 연산

zlib 명령어는 Jean-loup Gailly와 Mark Adler가 만든 Zlib 라이브러리의 압축·체크섬 기능을 Tcl에서 쓸 수 있게 해줘요. 문자열을 한 번에 압축·해제하는 기본 서브명령어부터, 채널에 변환을 붙이는 방식, 스트리밍 방식, Adler-32/CRC-32 체크섬까지 여러 층으로 기능이 나뉘어 있어요. 정확한 형식(compress/deflate와 gzip)과 해당하는 대칭 연산을 구분하는 게 핵심이에요.

출처: 문서

본문

문법

zlib subcommand arg ...

zlib 명령어는 Jean-loup Gailly와 Mark Adler가 만든 Zlib 라이브러리의 압축 및 체크섬 기능에 접근하게 해줘요. 다음과 같은 서브명령어들이 있어요.

압축 서브명령어

zlib compress string ?level?

string 안의 이진 문자열을 zlib-format으로 압축한 이진 데이터를 반환해요. level이 있으면 사용할 압축 레벨을 나타내요(0은 무압축, 9는 최대 압축).

zlib decompress string ?bufferSize?

string 안의 raw 압축 이진 데이터를 압축 해제한 버전을 반환해요. bufferSize가 있으면 데이터를 받는 데 쓸 버퍼 크기의 힌트예요.

zlib deflate string ?level?

string 안의 이진 문자열을 raw 압축 이진 데이터로 반환해요. level이 있으면 압축 레벨을 나타내요(0은 무압축, 9는 최대 압축).

zlib gunzip string ?-headerVar varName?

gzip 형식이었어야 하는 이진 문자열 string의 압축을 해제한 내용을 반환해요. -headerVar가 주어지면, gzip 헤더의 내용을 설명하는 딕셔너리를 varName 변수에 저장해요. 딕셔너리에 있을 수 있는 키는 다음과 같아요.

  • comment — 헤더의 주석 필드(있을 경우)
  • crc — 헤더의 CRC를 계산하는지 여부를 나타내는 boolean 값
  • filename — 헤더의 파일 이름 필드(있을 경우)
  • os — 헤더의 운영체제 유형 코드 필드(알려지지 않은 값이 아니면). 이 코드들의 의미는 RFC 1952 참조.
  • size — 압축 해제된 데이터의 크기
  • time — 0이 아닐 경우 헤더의 시간 필드로, filename 필드가 가리키는 파일이 수정된 시각일 것으로 예상됨. clock format에 쓰기 적합함.
  • type — 압축 해제된 데이터의 유형(알려진 경우 binary 또는 text)
zlib gzip string ?-level level? ?-header dict?

string 안의 이진 문자열을 gzip 형식으로 압축한 내용을 반환해요. -level이 주어지면 압축 레벨을 나타내요(0은 무압축, 9는 최대 압축). -header가 주어지면 dict는 gzip 헤더에 쓰이는 값들을 담은 딕셔너리예요. 정의할 수 있는 키는 다음과 같아요.

  • comment — 주어진 주석을 gzip 형식 데이터의 헤더에 추가
  • crc — 헤더의 CRC를 계산할지 여부를 나타내는 boolean. 데이터를 gzip 프로그램과 교환하려면 헤더 CRC를 계산하면 안 된다는 점에 주의.
  • filename — 압축할 데이터가 온 파일의 이름
  • os — 운영체제 유형 코드로, RFC 1952에서 설명하는 값 중 하나여야 함
  • timefilename 키가 가리키는 파일이 마지막으로 수정된 시각. clock secondsfile mtime이 반환하는 것과 같은 형식.
  • type — 압축 중인 데이터의 유형으로, binary 또는 text
zlib inflate string ?bufferSize?

string 안의 raw 압축 이진 데이터를 압축 해제한 버전을 반환해요. bufferSize가 있으면 데이터를 받는 데 쓸 버퍼 크기의 힌트예요.

채널 서브명령어

zlib push mode channel ?options ...?

channel 채널에 압축 또는 압축 해제 변환을 push해요. 변환은 chan pop으로 다시 제거할 수 있어요. mode 인자는 어떤 종류의 변환을 push할지 결정하며, 다음을 지원해요.

  • compresschannel(쓰기 가능해야 함)에 zlib 형식 데이터를 만드는 압축 변환
  • decompresschannel(읽기 가능해야 함)에서 zlib 형식 데이터를 읽는 압축 해제 변환
  • deflatechannel(쓰기 가능해야 함)에 raw 압축 데이터를 만드는 압축 변환
  • gunzipchannel(읽기 가능해야 함)에서 gzip 형식 데이터를 읽는 압축 해제 변환
  • gzipchannel(쓰기 가능해야 함)에 gzip 형식 데이터를 만드는 압축 변환
  • inflatechannel(읽기 가능해야 함)에서 raw 압축 데이터를 읽는 압축 해제 변환

zlib push 명령어의 options ...로 변환을 만들 때 다음 옵션을 설정할 수 있어요.

-dictionary binData

압축하거나 압축 해제할 데이터를 다룰 때 쓸 압축 딕셔너리를 binData로 설정해요. gzip 형식 데이터를 다루는 변환에는 유효하지 않아요. 딕셔너리는 이후 압축할 데이터에서 나올 법한 문자열(바이트 시퀀스)들로 구성해야 하고, 가장 흔히 쓰는 문자열을 딕셔너리 끝쪽에 두는 게 좋아요. Tcl은 특정 데이터 시퀀스에 좋은 딕셔너리를 고르는 메커니즘을 제공하지 않아요.

-header dictionary

만들 gzip 헤더의 설명을 zlib gzip이 이해하는 것과 같은 형식으로 전달해요.

-level compressionLevel

데이터를 얼마나 강하게 압축할지. 0(무압축)부터 9(최대 압축)까지의 정수여야 해요.

-limit readaheadLimit

압축 해제할 때 앞으로 읽을 최대 바이트 수.

이 옵션은 이제 무의미해졌어요. 원래는 다중 스트림 채널에서 Tcl이 압축 스트림 끝을 넘어 읽는 것을 막아, 그 뒤의 데이터를 더 읽기 위해 남겨두려고 도입됐어요(속도는 희생하고). 이제 Tcl은 압축 스트림 끝을 넘어 읽은 바이트를 자동으로 채널에 되돌려, 이후 읽는 쪽에는 읽히지 않은 것처럼 보이게 해요.

압축 및 압축 해제 채널 변환 모두 chan configure로 접근할 수 있는 추가 구성 옵션을 더해요.

-checksum checksum

읽기 전용 옵션으로, 압축 엔진이 지금까지 본 압축 해제 데이터의 현재 체크섬을 얻어요. 압축·압축 해제 변환 모두에 유효하지만 raw inflate·deflate 형식에는 유효하지 않아요. 압축 알고리즘은 만들거나 소비하는 형식에 따라 달라져요.

-dictionary binData

읽기-쓰기 옵션으로, 압축하거나 압축 해제할 데이터를 다룰 때 쓸 초기 압축 딕셔너리를 얻거나 설정해요. gzip 형식 데이터를 다루는 변환에는 유효하지 않고, 변환이 쌓이는 지점 외의 압축 변환에는 보통 설정하면 안 돼요. 이것으로 스트림 중간의 현재 활성 압축 딕셔너리를 얻을 수는 없다는 점에 주의하세요. 그 정보는 기본 라이브러리가 노출하지 않아요.

-flush type

쓰기 전용 연산으로, 압축기의 현재 상태를 기본 채널로 플러시해요. 압축 변환에만 유효해요. type은 일반 플러시에는 sync, 비용이 큰 플러시에는 full이어야 해요. 플러시는 압축률을 떨어뜨리지만, 데이터 손상 시 압축 해제기가 파일의 더 많은 부분을 복구하기 쉽게 해줘요.

-header dictionary

읽기 전용 옵션으로, gzip 형식 데이터를 처리하는 압축 해제 변환에만 유효하며, 데이터 스트림에서 읽은 헤더를 설명하는 딕셔너리를 반환해요.

-limit readaheadLimit

읽기-쓰기 옵션으로, 압축 해제 채널이 기본 데이터 소스에서 앞으로 읽을 최대 바이트 수를 제어하는 데 쓰여요. 자세한 내용은 위 참조.

스트리밍 서브명령어

zlib stream mode ?options?

mode에 기반한 스트리밍 압축 또는 압축 해제 명령어를 만들고, 그 명령어의 이름을 반환해요. 그 명령어가 어떻게 동작하는지는 아래 'STREAMING INSTANCE COMMAND' 참조. 지원되는 모드와 옵션은 다음과 같아요.

zlib stream compress ?-dictionary bindata? ?-level level?

zlib 형식 출력을 만드는 압축 스트림. level(지정 시)은 0~9 정수, bindata(지정 시)는 압축 딕셔너리.

zlib stream decompress ?-dictionary bindata?

zlib 형식 입력을 받아 압축 해제된 출력을 만드는 압축 해제 스트림. bindata가 제공되면 필요 시 쓸 압축 딕셔너리.

zlib stream deflate ?-dictionary bindata? ?-level level?

raw 출력을 만드는 압축 스트림. level(지정 시)은 0~9 정수, bindata(지정 시)는 압축 딕셔너리. raw 압축 데이터에는 어떤 압축 딕셔너리를 썼는지에 대한 메타데이터가 포함되지 않는다는 점에 주의(zlib 형식 데이터의 특징).

zlib stream gunzip

gzip 형식 입력을 받아 압축 해제된 출력을 만드는 압축 해제 스트림.

zlib stream gzip ?-header header? ?-level level?

gzip 형식 출력을 만드는 압축 스트림. level(지정 시)은 0~9 정수, header(지정 시)는 헤더 설명자 딕셔너리(키는 zlib gzip 참조).

zlib stream inflate ?-dictionary bindata?

raw 압축 입력을 받아 압축 해제된 출력을 만드는 압축 해제 스트림. bindata가 제공되면 쓸 압축 딕셔너리. 압축 딕셔너리가 올바른지 판별하는 검사는 없다는 점에 주의.

체크섬 서브명령어

zlib adler32 string ?initValue?

Adler-32 알고리즘으로 이진 문자열 string의 체크섬을 계산해요. initValue가 주어지면 체크섬 엔진 초기화에 쓰여요.

zlib crc32 string ?initValue?

CRC-32 알고리즘으로 이진 문자열 string의 체크섬을 계산해요. initValue가 주어지면 체크섬 엔진 초기화에 쓰여요.

스트리밍 인스턴스 명령어

스트리밍 압축 인스턴스 명령어는 zlib stream 명령어로 만들어져요. put 서브명령어를 한 번 이상 호출해 데이터를 넣고, get 서브명령어를 한 번 이상 호출해 변환된 데이터를 꺼내는 방식으로 사용해요.

스트리밍 인스턴스 명령어 stream이 지원하는 전체 서브명령어 집합은 다음과 같아요.

stream add ?option...? data

stream put ?option...? data에 이어 stream get을 호출하는 단축.

stream checksum

이 스트림이 지금까지 본 압축 해제 데이터의 체크섬을 반환.

stream close

이 스트림을 삭제하고 관련된 모든 자원을 해제.

stream eof

(압축 데이터 자체로 판단한) 스트림의 끝에 도달했는지 boolean으로 반환. 모든 형식이 스트림 끝 감지를 지원하는 건 아님.

stream finalize

stream put -finalize {}의 단축.

stream flush

stream put -flush {}의 단축.

stream fullflush

stream put -fullflush {}의 단축.

stream get ?count?

변환을 적용한 stream의 내부 버퍼에서 최대 count 바이트를 반환. count를 생략하면 버퍼 전체 내용을 반환.

stream header

스트림에서 추출한 gzip 헤더 설명 딕셔너리를 반환. gunzip으로 mode를 설정해 만든 스트림에서만 지원.

stream put ?option...? data

이진 문자열 data의 내용을 변환을 적용하면서 stream의 내부 버퍼에 추가. 변환 적용 방식을 수정하는 다음 옵션을 지원(혹은 그 모호하지 않은 프리픽스):

-dictionary binData

압축하거나 압축 해제할 데이터를 다룰 때 쓸 압축 딕셔너리를 binData로 설정.

-finalize

스트림을 끝났다고 표시해 모든 바이트가 완전히 압축·압축 해제되도록 보장. gzip 스트림은 푸터도 스트림에 쓰이도록 보장. 이후 이 옵션을 쓴 뒤에는 더 많은 데이터를 쓰기 전에 스트림을 reset해야 하지만, get 서브명령어로 스트림에서 데이터를 여전히 읽을 수 있음. -flush-fullflush 옵션과 상호 배타적.

-flush

현재 (압축) 스트림이 만들어 내는 바이트를 소비하는 압축 해제기가, 지금까지 압축된 모든 바이트를 만들어낼 수 있도록 보장(어느 정도 성능 비용과 함께). -finalize-fullflush 옵션과 상호 배타적.

-fullflush

압축 해제기가 지금까지 만들어진 모든 바이트를 처리할 수 있을 뿐 아니라, 스트림이 부분적으로 손상됐음을 감지하면 이 지점부터 다시 시작할 수 있도록 보장. 상당한 성능 비용이 따름. -finalize-flush 옵션과 상호 배타적.

stream reset

finalize됐거나 eof에 도달한 스트림을 포함해 어떤 스트림이든 다시 더 많은 데이터를 처리할 수 있는 상태로 되돌려요. 내부적으로 버퍼링된 모든 데이터를 버려요.

예제

Tcl 문자열을 압축하려면, zlib 명령어가 항상 이진 문자열을 다루므로 먼저 특정 문자셋 인코딩으로 변환해야 해요.

set binData [encoding convertto utf-8 $string]
set compData [zlib compress $binData]

다시 되돌릴 때도 문자셋 인코딩을 반대로 적용하는 게 중요해요.

set binData [zlib decompress $compData]
set string [encoding convertfrom utf-8 $binData]

위 압축 연산은 스트림으로도 할 수 있는데, 데이터를 단계별로 축적하고 싶을 때 특히 유용해요.

set strm [zlib stream compress]
$strm put [encoding convertto utf-8 $string]
# ...
$strm finalize
set compData [$strm get]
$strm close

더 알아보기

  • binary, chan, encoding, Tcl_ZlibDeflate — 이진 데이터·채널·인코딩 관련 명령어, RFC1950–RFC1952
  • 관련 키워드: compress, decompress, deflate, gzip, inflate, zlib