home *** CD-ROM | disk | FTP | other *** search
/ AmigActive 15 / AACD15.ISO / AACD / Programming / Python2 / Python20_source / Misc / distutils / extract.c < prev    next >
Encoding:
C/C++ Source or Header  |  2000-10-25  |  6.2 KB  |  260 lines

  1. #include <windows.h>
  2.  
  3. #define ZLIB_DLL
  4. #include "zlib/zlib.h"
  5.  
  6. #include <stdio.h>
  7. #include <stdarg.h>
  8.  
  9. #include "archive.h"
  10.  
  11. /* Convert unix-path to dos-path */
  12. static void fixpath (char *path)
  13. {
  14.     while (path && *path) {
  15.     if (*path == '/')
  16.         *path = '\\';
  17.     ++path;
  18.     }
  19. }
  20.  
  21. BOOL ensure_directory (char *pathname, char *new_part, NOTIFYPROC notify)
  22. {
  23.     while (new_part && *new_part && (new_part = strchr (new_part, '\\'))) {
  24.     DWORD attr;
  25.     *new_part = '\0';
  26.     attr = GetFileAttributes (pathname);
  27.     if (attr == -1) {
  28.         /* nothing found */
  29.         if (!CreateDirectory (pathname, NULL) && notify)
  30.         notify (SYSTEM_ERROR, "CreateDirectory (%s)", pathname);
  31.     }
  32.     if (attr & FILE_ATTRIBUTE_DIRECTORY) {
  33.         ;
  34.     } else {
  35.         SetLastError (183);
  36.         if (notify)
  37.         notify (SYSTEM_ERROR, "CreateDirectory (%s)", pathname);
  38.     }
  39.     *new_part = '\\';
  40.     ++new_part;
  41.     }
  42.     return TRUE;
  43. }
  44.  
  45. /* XXX Should better explicitely specify
  46.  * uncomp_size and file_times instead of pfhdr!
  47.  */
  48. char *map_new_file (DWORD flags, char *filename,
  49.             char *pathname_part, int size,
  50.             WORD wFatDate, WORD wFatTime,
  51.             NOTIFYPROC notify)
  52. {
  53.     HANDLE hFile, hFileMapping;
  54.     char *dst;
  55.     FILETIME ft;
  56.  
  57.   try_again:
  58.     if (!flags)
  59.     flags = CREATE_NEW;
  60.     hFile = CreateFile (filename,
  61.             GENERIC_WRITE | GENERIC_READ,
  62.             0, NULL,
  63.             flags,
  64.             FILE_ATTRIBUTE_NORMAL, NULL);
  65.     if (hFile == INVALID_HANDLE_VALUE) {
  66.     DWORD x = GetLastError();
  67.     switch (x) {
  68.     case ERROR_FILE_EXISTS:
  69.         if (notify && notify (CAN_OVERWRITE, filename))
  70.                hFile = CreateFile (filename,
  71.                     GENERIC_WRITE | GENERIC_READ,
  72.                     0, NULL,
  73.                     CREATE_ALWAYS,
  74.                     FILE_ATTRIBUTE_NORMAL, NULL);
  75.         else {
  76.         if (notify)
  77.             notify (FILE_OVERWRITTEN, filename);
  78.         return NULL;
  79.         }
  80.         break;
  81.     case ERROR_PATH_NOT_FOUND:
  82.         if (ensure_directory (filename, pathname_part, notify))
  83.         goto try_again;
  84.         else
  85.         return FALSE;
  86.         break;
  87.     default:
  88.         SetLastError (x);
  89.         break;
  90.     }
  91.     }
  92.     if (hFile == INVALID_HANDLE_VALUE) {
  93.     if (notify)
  94.         notify (SYSTEM_ERROR, "CreateFile (%s)", filename);
  95.     return NULL;
  96.     }
  97.  
  98.     if (notify)
  99.     notify (FILE_CREATED, filename);
  100.  
  101.     DosDateTimeToFileTime (wFatDate, wFatTime, &ft);
  102.     SetFileTime (hFile, &ft, &ft, &ft);
  103.  
  104.  
  105.     if (size == 0) {
  106.     /* We cannot map a zero-length file (Also it makes
  107.        no sense */
  108.     CloseHandle (hFile);
  109.     return NULL;
  110.     }
  111.  
  112.     hFileMapping = CreateFileMapping (hFile,
  113.                       NULL, PAGE_READWRITE, 0, size, NULL);
  114.  
  115.     CloseHandle (hFile);
  116.  
  117.     if (hFileMapping == INVALID_HANDLE_VALUE) {
  118.     if (notify)
  119.         notify (SYSTEM_ERROR, "CreateFileMapping (%s)", filename);
  120.     return NULL;
  121.     }
  122.  
  123.     dst = MapViewOfFile (hFileMapping,
  124.              FILE_MAP_WRITE, 0, 0, 0);
  125.  
  126.     CloseHandle (hFileMapping);
  127.  
  128.     if (!dst) {
  129.     if (notify)
  130.         notify (SYSTEM_ERROR, "MapViewOfFile (%s)", filename);
  131.     return NULL;
  132.     }
  133.     return dst;
  134. }
  135.  
  136.  
  137. BOOL
  138. extract_file (char *dst, char *src, int method, int comp_size,
  139.           int uncomp_size, NOTIFYPROC notify)
  140. {
  141.     z_stream zstream;
  142.     int result;
  143.  
  144.     if (method == Z_DEFLATED) {
  145.     int x;
  146.         memset (&zstream, 0, sizeof (zstream));
  147.         zstream.next_in = src;
  148.         zstream.avail_in = comp_size+1;
  149.     zstream.next_out = dst;
  150.         zstream.avail_out = uncomp_size;
  151.  
  152. /* Apparently an undocumented feature of zlib: Set windowsize
  153.  to negative values to supress the gzip header and be compatible with
  154.  zip! */
  155.     result = TRUE;
  156.         if (Z_OK != (x = inflateInit2(&zstream, -15))) {
  157.         if (notify)
  158.         notify (ZLIB_ERROR, "inflateInit2 returns %d", x);
  159.         result = FALSE;
  160.         goto cleanup;
  161.     }
  162.     if (Z_STREAM_END != (x = inflate(&zstream, Z_FINISH))) {
  163.         if (notify)
  164.         notify (ZLIB_ERROR, "inflate returns %d", x);
  165.         result = FALSE;
  166.     }
  167.       cleanup:
  168.     if (Z_OK != (x = inflateEnd(&zstream))) {
  169.         if (notify)
  170.         notify (ZLIB_ERROR, "inflateEnd returns %d", x);
  171.         result = FALSE;
  172.     }
  173.     } else if (method == 0) {
  174.     memcpy(dst, src, uncomp_size);
  175.     result = TRUE;
  176.     } else
  177.     result = FALSE;
  178.     UnmapViewOfFile(dst);
  179.     return result;
  180. }
  181.  
  182. /* Open a zip-compatible archive and extract all files
  183.  * into the specified directory (which is assumed to exist)
  184.  */
  185. BOOL
  186. unzip_archive (char *dirname, char *data, DWORD size, NOTIFYPROC notify)
  187. {
  188.     int n;
  189.     char pathname[MAX_PATH];
  190.     char *new_part;
  191.  
  192.     /* read the end of central directory record */
  193.     struct eof_cdir *pe = (struct eof_cdir *)&data[size - sizeof
  194.                           (struct eof_cdir)];
  195.  
  196.     int arc_start = size - sizeof (struct eof_cdir) - pe->nBytesCDir -
  197.     pe->ofsCDir;
  198.  
  199.     /* set position to start of central directory */
  200.     int pos = arc_start + pe->ofsCDir;
  201.  
  202.     /* make sure this is a zip file */
  203.     if (pe->tag != 0x06054b50)
  204.     return FALSE;
  205.     
  206.     /* Loop through the central directory, reading all entries */
  207.     for (n = 0; n < pe->nTotalCDir; ++n) {
  208.     char *fname;
  209.     char *pcomp;
  210.     char *dst;
  211.     struct cdir *pcdir = (struct cdir *)&data[pos];
  212.     struct fhdr *pfhdr = (struct fhdr *)&data[pcdir->ofs_local_header +
  213.                          arc_start];
  214.  
  215.         if (pcdir->tag != 0x02014b50)
  216.         return FALSE;
  217.     if (pfhdr->tag != 0x04034b50)
  218.         return FALSE;
  219.     pos += sizeof (struct cdir);
  220.     fname = (char *)&data[pos]; /* This is not null terminated! */
  221.     pos += pcdir->fname_length + pcdir->extra_length +
  222.         pcdir->comment_length;
  223.  
  224.     pcomp = &data[pcdir->ofs_local_header
  225.              + sizeof (struct fhdr)
  226.              + arc_start
  227.              + pfhdr->fname_length
  228.              + pfhdr->extra_length];
  229.  
  230.     strcpy (pathname, dirname);
  231.     strcat (pathname, "\\");
  232.     new_part = &pathname[lstrlen (pathname)];
  233.     strncat (pathname, fname, pfhdr->fname_length);
  234.     fixpath (pathname);
  235.     if (pathname[strlen(pathname)-1] != '\\') {
  236.         /*
  237.          * The local file header (pfhdr) does not always contain
  238.          * the compressed and uncompressed sizes of the data
  239.          * depending on bit 3 of the flags field.
  240.          * So it seems better to use the data from the
  241.          * central directory (pcdir).
  242.          */
  243.         dst = map_new_file (0, pathname, new_part,
  244.                 pcdir->uncomp_size,
  245.                 pcdir->last_mod_file_date,
  246.                 pcdir->last_mod_file_time, notify);
  247.         if (dst) {
  248.         if (!extract_file (dst, pcomp, pfhdr->method,
  249.                    pcdir->comp_size, pcdir->uncomp_size,
  250.                    notify))
  251.             return FALSE;
  252.         } /* else ??? */
  253.     }
  254.     if (notify)
  255.         notify (NUM_FILES, new_part, (int)pe->nTotalCDir,
  256.             (int)n+1);
  257.     }
  258.     return TRUE;
  259. }
  260.