압축해제 프로그램 제작 

  • 이제 압축 해제 프로그램을 제작해보자.
  • 여기서는 그냥 무압축된 zip파일을 해제해 보도록하겠다.
  • 앞서 3번째 강좌 ( http://fehead.tistory.com/164 )에서 zip localheader file을 이용한 파일 리스트 보기 소스를 기억하는가?
  • 거기 파일리스트를 출력하는 바로위에 아래 한줄만 추가해보자. 

        // 추가된소스 한줄
        unzip(filename, data, l.compressed_size);

        // 원래 소스
        printf("%s\tCompressed size:%u\t Uncompressed size:%u\n",
                filename, l.compressed_size, l.uncompressed_size);

  • 자 이제 위 내용을 main 함수위에 코딩하면된다. 

// 압축파일 해제

void unzip(const char * filename, const char * data, ulong size)
{
    // 파일을 연다.
    FILE *  file = fopen(filename, "w");
    if(file == 0)
    {
        perror("fopen:");
        return;
    }

    // 파일에 데이터를 쓴다.
    fwrite(data, 1, size, file);

    // 파일을 닫는다.
    fclose(file);
}



# 컴파일
$ gcc -o tunzip tunzip.challo


# 테스트를 하기 위해 임시 디렉토리 생성
$ mkdir tmp

# test.zip 파일과 방금 만든 프로그램을 임시 디렉토리로 복사.
$ cp test.zip tunzip tmp

# 임시 디렉토리로 이동
cd tmp
$ ls -l
합계 12
-rw-r--r-- 1 fehead users  334  8월 18 18:18 test.zip
-rwxr-xr-x 1 fehead users 6446  8월 18 18:18 tunziphallo

# 프로그램 실행
$ ./tunzip 
aa.txt  Compressed size:16       Uncompressed size:16
bb.txt  Compressed size:16       Uncompressed size:16

# 압축 풀린것 확인.
$ ls -l
합계 20
-rw-r--r-- 1 fehead users   16  8월 18 18:18 aa.txt
-rw-r--r-- 1 fehead users   16  8월 18 18:18 bb.txt
-rw-r--r-- 1 fehead users  334  8월 18 18:18 test.zip
-rwxr-xr-x 1 fehead users 6446  8월 18 18:18 tunzip

# 내용물 확인.
$ cat aa.txt
0123456789ABCDEF


  • 압축 해제 프로그램을 작성했다.. 와!!!
  • 몇 강좌후에 진짜 압축된 파일도 한번 압축해보자. 

  • 다음강좌는 파일을 무압축으로 zip파일을 만들어보는것을 해보도록하자.

     전체소스는 아래 첨부파일을 참고 하세요. 
    압축파일
     
    소스
     

zip 파일목록 보여주기 프로그램 작성 2번째 


  • 이번에는 Central directory file header를 이용해서 파일 목록을 보여줘보도록하시죠 

  • end of central directory record 구조체 작성
// Zip end of central directory record - Signature = 0x06054b50
struct _zip_end_central_h
{   
    ushort  number;         // Number of this disk
    ushort  start;          // Disk where central directory starts
    ushort  record_cnt;     // Number of central directory records on this disk
    ushort  totoal_record_cnt;  // Total number of central directory records
    ulong   central_size;   // Size of central directory (bytes)
    ulong   offset;         // Offset of start of central directory
    ushort  comment_len;    // ZIP file comment length (n)
} __attribute__((packed));
typedef struct _zip_end_central_h zip_end_central_h;


  • Central directory file header구조체 작성
// Central directory file header -  signature = 0x02014b50
struct _zip_cetral_h
{
    ushort  ver_m;      // Version made by
    ushort  ver_n;      // Version needed to extract (minimum)
    ushort  flag;       // General purpose bit flag
    ushort  method;     // Compression method
    ushort  time;       // File last modification time
    ushort  date;       // File last modification date
    ulong   crc;        // CRC-32
    ulong   compressed_size;    // Compressed size
    ulong   uncompressed_size;  // Uncompressed size
    ushort  filename_len;       // File name length (n)
    ushort  extra_len;          // Extra field length (m)
    ushort  comment_len;        // File comment length (k)
    ushort  starts;             // Disk number where file starts
    ushort  i_attributes;       // Internal file attributes
    ulong   e_attributes;       // External file attributes
    ulong   relative_offset;    // Relative offset of local file header.
} __attribute__((packed));
typedef struct _zip_cetral_h zip_cetral_h;



  • main 작성
 
1 // test.zip 파일 을 연다.
2 // 파일 위치를 끝으로 이동.
3 // end of central directory records 를 찾을때까지 반복.
4
5 // 못찾았으면 종료.
6 // 찾았다면 centrol directory file header로 이동한다.
7 // 파일 끝까지 반복한다.
8     // 시그너처를 읽는다.
9     // centrol directory signature 가 아니면
10         // break;
11     // centrol directory 구조체를 읽어들인다.
12     // 파일이름을 읽어들인다.
13     // extra data와 file comment를 읽어들인다.
14     // 파일명과 압축된 파일 용량을 출력한다.
15 // 파일을 닫는다.

  • 완전소스
// zipinfo2.c
// http:://fehead.tistory.com
#include <stdio.h>
#include <stdlib.h>

typedef unsigned short  ushort;
typedef unsigned long   ulong;

// Zip end of central directory record - Signature = 0x06054b50
struct _zip_end_central_h
{
        ushort  number;                 // Number of this disk
        ushort  start;                  // Disk where central directory starts
        ushort  record_cnt;             // Number of central directory records on this disk
        ushort  totoal_record_cnt;      // Total number of central directory records
        ulong   central_size;   // Size of central directory (bytes)
        ulong   offset;                 // Offset of start of central directory
        ushort  comment_len;    // ZIP file comment length (n)
} __attribute__((packed));
typedef struct _zip_end_central_h zip_end_central_h;

// Central directory file header -  signature = 0x02014b50
struct _zip_cetral_h
{
        ushort  ver_m;          // Version made by
        ushort  ver_n;          // Version needed to extract (minimum)
        ushort  flag;           // General purpose bit flag
        ushort  method;         // Compression method
        ushort  time;           // File last modification time
        ushort  date;           // File last modification date
        ulong   crc;            // CRC-32
        ulong   compressed_size;        // Compressed size
        ulong   uncompressed_size;      // Uncompressed size
        ushort  filename_len;           // File name length (n)
        ushort  extra_len;                      // Extra field length (m)
        ushort  comment_len;            // File comment length (k)
        ushort  starts;                         // Disk number where file starts
        ushort  i_attributes;           // Internal file attributes
        ulong   e_attributes;           // External file attributes
        ulong   relative_offset;        // Relative offset of local file header.
} __attribute__((packed));
typedef struct _zip_cetral_h zip_cetral_h;


int main()
{
        // test.zip 파일 을 연다.
        FILE *  zip_file = 0;
        zip_file = fopen("test.zip""r");
        if(zip_file == 0)
        {
                perror("fopen:");
                return 0;
        }

        // end of central directory records를 찾는다.
        ulong   signature = 0;
        long    pos = (long)sizeof(zip_end_central_h) + sizeof(signature);
        fseek(zip_file, -pos, SEEK_END);

        fread(&signature, 1sizeof(signature), zip_file);

        // 못찾았으면 종료.
        if(signature != 0x06054b50)
        {
                fprintf(stderr"not found end of central directory records\n");
                return 0;
        }

        // 찾았다면 centrol directory file header로 이동한다.
        zip_end_central_h       e;
        fread(&e, 1sizeof(zip_end_central_h), zip_file);
        fseek(zip_file, e.offset, SEEK_SET);

        // 파일 끝까지 반복한다.
        int i = 0;
        for(i = 0 ; i < e.totoal_record_cnt ; ++i)
        {
                // 시그너처를 읽는다.
                fread(&signature, 1sizeof(signature), zip_file);

                // centrol directory signature 가 아니면
                if(signature != 0x02014b50)
                        break;

                // centrol directory 구조체를 읽어들인다.
                zip_cetral_h    c;
                fread(&c, 1sizeof(c), zip_file);

                // 파일이름을 읽어들인다.
                char * filename = (char *)malloc(c.filename_len + 1);
                fread(filename, 1, c.filename_len, zip_file);
                filename[c.filename_len] = 0;

                // extra data와 file comment를 읽어들인다. 그냥 넘긴다.
                fseek(zip_file, c.extra_len, SEEK_CUR);
                fseek(zip_file, c.comment_len, SEEK_CUR);

                // 파일명과 압축된 파일 용량을 출력한다.
                printf("%s\tCompressed size:%u\t Uncompressed size:%u\n",
                                filename, c.compressed_size, c.uncompressed_size);

                free(filename);

        }
        // 파일을 닫는다.
        fclose(zip_file);

        return 0;
}


  • 결과
$ ./zipinfo2 
aa.txt	Compressed size:16	 Uncompressed size:16
bb.txt	Compressed size:16	 Uncompressed size:16

zip 파일목록 보여주기 프로그램 작성 첫번째


  • zip local file header 구조체 작성

typedef unsigned short  ushort;
typedef unsigned long   ulong;


// Zip Local file header static
struct _zip_localfile_h
{
    ushort  ver;        // Version needed to extract (minimum)
    ushort  flag;       // General purpose bit flag
    ushort  method;     // Compression method
    ushort  time;       // File last modification time
    ushort  date;       // File last modification date
    ulong   crc;        // CRC-32
    ulong   compressed_size;    // Compressed size
    ulong   uncompressed_size;  // Uncompressed size
    ushort  filename_len;       // File name length (n)
    ushort  extra_len;          // Extra field length (m)
} __attribute__((packed));
typedef struct _zip_localfile_h zip_localfile_h;


  • main 작성

// "test.zip" 파일을 연다.
// 파일끝까지 반복한다.
   // 4바이트 시그너처를 읽어들인다.
   // zip local file header 시그너처가 아니면(0x04034b50)
      // break;
   // zip_localfile_h struct를 파일에서 읽어들인다.
   // 파일이름을 읽어들인다.
   // extra field를 읽어들인다.
   // 압축 데이터를 읽어들인다.
   // 파일 이름과 파일 크기등을 화면에 뿌린다.
// 파일을 닫는다.

  • 완전소스

// zipinfo.c
// http:://fehead.tistory.com
#include <stdio.h>
#include <stdlib.h>

typedef unsigned short  ushort;
typedef unsigned long   ulong;

// Zip Local file header static
struct _zip_localfile_h
{
    ushort  ver;        // Version needed to extract (minimum)
    ushort  flag;       // General purpose bit flag
    ushort  method;     // Compression method
    ushort  time;       // File last modification time
    ushort  date;       // File last modification date
    ulong   crc;        // CRC-32
    ulong   compressed_size;    // Compressed size
    ulong   uncompressed_size;  // Uncompressed size
    ushort  filename_len;       // File name length (n)
    ushort  extra_len;          // Extra field length (m)
} __attribute__((packed));int argc, char * argv[]
typedef struct _zip_localfile_h zip_localfile_h;

// main
int main()
{

    // "test.zip" 파일을 연다.
    FILE *  zip_file = 0;
    zip_file = fopen("test.zip""r");
    if(zip_file == 0)
    {
        perror("fopen:");
        return 0;
    }

    // 파일끝까지 반복한다.
    while(feof(zip_file) == 0)
    {

        // 4바이트 시그너처를 읽어들인다.
        ulong   signature;
        if(sizeof(signature) !=
                fread(&signature, 1sizeof(signature), zip_file))
        {
            fprintf(stderr,"zip file error\n");
            break;
        }

        // zip local file header 시그너처가 아니면(0x04034b50) break;
        if(signature != 0x04034b50)
        {
            printf("signature : %#x\n", signature);
            break;
        }

        // zip_localfile_h struct를 파일에서 읽어들인다.
        zip_localfile_h l;
        fread(&l, sizeof(l), 1, zip_file);

        char * filename = (char *)malloc(l.filename_len + 1);
        char * extra = (char *)malloc(l.extra_len);
        char * data = (char *)malloc(l.compressed_size);

        // 파일이름을 읽어들인다.
        fread(filename, 1, l.filename_len, zip_file);
        filename[l.filename_len] = '\0';

        // extra field를 읽어들인다.
        fread(extra, 1, l.extra_len, zip_file);

        // 압축 데이터를 읽어들인다.
        fread(data, 1, l.compressed_size, zip_file);

        // 파일 이름과 파일 크기등을 화면에 뿌린다.
        printf("%s\tCompressed size:%u\t Uncompressed size:%u\n",
                filename, l.compressed_size, l.uncompressed_size);

       
free(data);
        free(extra);
        free(filename);
    }

    // 파일을 닫는다.
    fclose(zip_file);
    return 0;
}

  • 결과
$ ./zipinfo 
aa.txt	Compressed size:16	 Uncompressed size:16
bb.txt	Compressed size:16	 Uncompressed size:16
signature : 0x2014b50

ZIP central directory file header 



Offset Bytes Description
0 4 Central directory file header signature = 0x02014b50
4 2 Version made by
6 2 Version needed to extract (minimum)
 8 2 General purpose bit flag
10 2 Compression method
12 2 File last modification time
14 2 File last modification date
16 4 CRC-32
20 4 Compressed size
24 4 Uncompressed size
28 2 File name length (n)
30 2 Extra field length (m)
32 2 File comment length (k)
34 2 Disk number where file starts
36 2 Internal file attributes
38 4 External file attributes
42 4 Relative offset of local file header. This is the number of bytes between
the start of the first disk on which the file occurs, and the start of
the local file header. This allows software reading the central directory
to locate the position of the file inside the ZIP file.
46 n File name
46+n m Extra field
46+n+m k File comment


  • 첫번째 ZIP central directory file header 분석 

$ xxd test.zip | grep -A 4 00000a0:
00000a0: 504b 0102 1e03 0a00 0000 0000 5189 093f  PK..........Q..?
00000b0: b537 3c98 1000 0000 1000 0000 0600 1800  .7<.............
00000c0: 0000 0000 0000 0000 a481 0000 0000 6161  ..............aa
00000d0: 2e74 7874 5554 0500 0379 eb40 4e75 780b  .txtUT...y.@Nux.
00000e0: 0001 04e8 0300 0004 6400 0000 504b 0102  ........d...PK..

Offset Bytes Description
0 4 signature = 0x02014b50 504b 0102
4 2 Version made by 1e03
6 2 Version needed to extract (minimum) 0a00
 8 2 General purpose bit flag 0000
10 2 Compression method 0000
12 2 last modification time 5189
14 2 last modification date 093f
16 4 CRC-32 b537 3c98
20 4 Compressed size 1000 0000
24 4 Uncompressed size 1000 0000
28 2 File name length (n) 0600
30 2 Extra field length (m) 1800
32 2 File comment length (k) 0000
34 2 Disk number where file starts 0000
36 2 Internal file attributes 0000
38 4 External file attributes 0000 a481
42 4 Relative offset of local file header 0000 0000
46 n File name 6161 2e74 7874 "aa.txt"
46+n m(0x18) Extra field
5554 0500 0379 eb40 4e75 780b 0001 04e8
0300 0004 6400 0000
46+n+m k(0x0) File comment


  • 두번째 ZIP central directory file header 분석
$ xxd -s 0xec test.zip 
00000ec: 504b 0102 1e03 0a00 0000 0000 6089 093f  PK..........`..?
00000fc: b537 3c98 1000 0000 1000 0000 0600 1800  .7<.............
000010c: 0000 0000 0000 0000 a481 5000 0000 6262  ..........P...bb
000011c: 2e74 7874 5554 0500 0394 eb40 4e75 780b  .txtUT.....@Nux.
000012c: 0001 04e8 0300 0004 6400 0000 504b 0506  ........d...PK..
....

은 알아서들 해보시고^^ 


ZIP end of central directory record 


Offset Bytes Description
 0 4 End of central directory signature = 0x06054b50
 4 2 Number of this disk
 6 2 Disk where central directory starts
 8 2 Number of central directory records on this disk
10 2 Total number of central directory records
12 4 Size of central directory (bytes)
16 4
20 2 ZIP file comment length (n)
22 n ZIP file comment



  • ZIP end of central directory record 분석 

$ xxd -s 0x138 test.zip 
0000138: 504b 0506 0000 0000 0200 0200 9800 0000  PK..............
0000148: a000 0000 0000                           ......

Offset Bytes Description
 0 4 Signature = 0x06054b50 504b 0506
 4 2 Number of this disk 0000
 6 2 Disk where central directory starts 0000
 8 2 Number of central directory records on this disk 0200
10 2 Total number of central directory records 0200
12 4 Size of central directory (bytes) 9800 0000
16 4 Offset of start of central directory a000 0000
20 2 ZIP file comment length (n) 0000
22 n ZIP file comment


이제 대략적인 분석은 끝났으므로 다음에는 zip파일을 가지고 프로그래밍 해보시죠.

ZIP local file header 

Local header 는 아래와 같고 [http]위키리스트참고

ZIP local file header
Offset Bytes Description
0 4 Local file header signature = 0x04034b50 (read as a little-endian number)
4 2 Version needed to extract (minimum)
6 2 General purpose bit flag
8 2 Compression method
10 2 File last modification time
12 2 File last modification date
14 4 CRC-32
18 4 Compressed size
22 4 Uncompressed size
26 2 File name length (n)
28 2 Extra field length (m)
30 n File name
30+n m Extra field

위에 나온 것을 보고 분석해봅시다.
$ xxd test.zip | head -6
0000000: 504b 0304 0a00 0000 0000 2cb2 093f b537  PK........,..?.7
0000010: 3c98 1000 0000 1000 0000 0600 1c00 6161  <.............aa
0000020: 2e74 7874 5554 0900 0363 3341 4e6a 3341  .txtUT...c3ANj3A
0000030: 4e75 780b 0001 046b 0400 0004 f901 0000  Nux....k........
0000040: 3031 3233 3435 3637 3839 4142 4344 4546  0123456789ABCDEF
0000050: 504b 0304 0a00 0000 0000 2fb2 093f b537  PK......../..?.7


Offset Bytes Description Value
0 4 Local file header signature 504b 0304
4 2 Version needed to extract (minimum) 0a00
6 2 General purpose bit flag 0000
8 2 Compression method 0000
10 2 File last modification time 5189
12 2 File last modification date 093f
14 4 CRC-32 b537 3c98
18 4 Compressed size 1000 0000
22 4 Uncompressed size 1000 0000
26 2 File name length (n) 0600
28 2 Extra field length (m) 1c00
30 n(6) File name 6161 2e74 7874("aa.txt")
30+n m(1c) Extra field(1c == 28byte)
0900 0379 eb40 4e94 eb40 4e75 780b 0001
04e8 0300 0004 6400 0000
30+n+m Data 3031 3233 3435 3637 3839 4142 4344 4546 = "0123456789ABCDEF"

두번째

$ xxd test.zip |grep -A 5 0000050
0000050: 504b 0304 0a00 0000 0000 6089 093f b537  PK........`..?.7
0000060: 3c98 1000 0000 1000 0000 0600 1c00 6262  <.............bb
0000070: 2e74 7874 5554 0900 0394 eb40 4e94 eb40  .txtUT.....@N..@
0000080: 4e75 780b 0001 04e8 0300 0004 6400 0000  Nux.........d...
0000090: 3031 3233 3435 3637 3839 4142 4344 4546  0123456789ABCDEF
00000a0: 504b 0102 1e03 0a00 0000 0000 5189 093f  PK..........Q..?

Offset Bytes Description Value
0 4 Local file header signature 504b 0304
4 2 Version needed to extract (minimum) 0a00
6 2 General purpose bit flag 0000
8 2 Compression method 0000
10 2 File last modification time 6089
12 2 File last modification date 093f
14 4 CRC-32 b537 3c98
18 4 Compressed size 1000 0000
22 4 Uncompressed size 1000 0000
26 2 File name length (n) 0600
28 2 Extra field length (m) 1c00
30 n(6) File name 6262 2e74 7874("bb.txt")
30+n m(1c) Extra field(1c == 28byte)
5554 0900 0394 eb40 4e94 eb40 4e75 780b
0001 04e8 0300 0004 6400 0000
30+n+m Data 3031 3233 3435 3637 3839 4142 4344 4546 = "0123456789ABCDEF"

순서 

  • 2개의 파일을 압축한 압축파일을 만들어본다.
  • 압축한 파일을 분석해본다.
  • 분석한 내용을 가지고 분석한 내용을 출력하는 프로그램을 만들어본다. 

분석할 압축파일 작성 

  • 2개의 파일을 압축한 압축파일을 만들어본다.
    파일 첨부 :
# "0123456789ABCDEF"의 내용이 있는 16바이트 텍스트 파일 2개 만들기
$ xxd -r > aa.txt
0000000: 3031 3233 3435 3637 3839 4142 4344 4546  # 화면에 입력할 내용

$ cp aa.txt bb.txt
$ cat aa.txt
0123456789ABCDEF

$ zip -0 test.zip aa.txt bb.txt   # aa.txt, bb.txt 파일을 압축하지 않고 test.zip 파일로만듬.
  adding: aa.txt (stored 0%)
  adding: bb.txt (stored 0%)

$ ls -l
-rw-r--r-- 1 fehead member  16  89 22:17 aa.txt
-rw-r--r-- 1 fehead member  16  89 22:17 bb.txt0
-rw-r--r-- 1 fehead member 334  89 22:21 test.zip

  • 압축한 파일 내용물 확인E
$ xxd test.zip
0000000: 504b 0304 0a00 0000 0000 2cb2 093f b537  PK........,..?.7
0000010: 3c98 1000 0000 1000 0000 0600 1c00 6161  <.............aa
0000020: 2e74 7874 5554 0900 0363 3341 4e6a 3341  .txtUT...c3ANj3A
0000030: 4e75 780b 0001 046b 0400 0004 f901 0000  Nux....k........

0000040: 3031 3233 3435 3637 3839 4142 4344 4546  0123456789ABCDEF
0000050: 504b 0304 0a00 0000 0000 2fb2 093f b537  PK......../..?.7
0000060: 3c98 1000 0000 1000 0000 0600 1c00 6262  <.............bb
0000070: 2e74 7874 5554 0900 036a 3341 4e6a 3341  .txtUT...j3ANj3A
0000080: 4e75 780b 0001 046b 0400 0004 f901 0000  Nux....k........
0000090: 3031 3233 3435 3637 3839 4142 4344 4546  0123456789ABCDEF
00000a0: 504b 0102 1e03 0a00 0000 0000 2cb2 093f  PK..........,..?
00000b0: b537 3c98 1000 0000 1000 0000 0600 1800  .7<.............
00000c0: 0000 0000 0000 0000 a481 0000 0000 6161  ..............aa
00000d0: 2e74 7874 5554 0500 0363 3341 4e75 780b  .txtUT...c3ANux.
00000e0: 0001 046b 0400 0004 f901 0000 504b 0102  ...k........PK..
00000f0: 1e03 0a00 0000 0000 2fb2 093f b537 3c98  ......../..?.7<.
0000100: 1000 0000 1000 0000 0600 1800 0000 0000  ................
0000110: 0000 0000 a481 5000 0000 6262 2e74 7874  ......P...bb.txt
0000120: 5554 0500 036a 3341 4e75 780b 0001 046b  UT...j3ANux....k
0000130: 0400 0004 f901 0000 504b 0506 0000 0000  ........PK......
0000140: 0200 0200 9800 0000 a000 0000 0000       ..............

이것을 가지고 분석해보자

먼저 zip file format 형태는 아래와 같습니다. [http]위키리스트참고



다음편에 계속...
  
파일 첨부함.

 

+ Recent posts