home *** CD-ROM | disk | FTP | other *** search
/ Tools / WinSN5.0Ver.iso / NETSCAP.50 / WIN1998.ZIP / ns / lib / libnet / cvunzip.c < prev    next >
Encoding:
C/C++ Source or Header  |  1998-04-08  |  12.7 KB  |  483 lines

  1. /* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*-
  2.  *
  3.  * The contents of this file are subject to the Netscape Public License
  4.  * Version 1.0 (the "NPL"); you may not use this file except in
  5.  * compliance with the NPL.  You may obtain a copy of the NPL at
  6.  * http://www.mozilla.org/NPL/
  7.  *
  8.  * Software distributed under the NPL is distributed on an "AS IS" basis,
  9.  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
  10.  * for the specific language governing rights and limitations under the
  11.  * NPL.
  12.  *
  13.  * The Initial Developer of this code under the NPL is Netscape
  14.  * Communications Corporation.  Portions created by Netscape are
  15.  * Copyright (C) 1998 Netscape Communications Corporation.  All Rights
  16.  * Reserved.
  17.  */
  18.  
  19. /* Please leave outside of ifdef for windows precompiled headers */
  20. #include "mkutils.h"
  21. #include "cvunzip.h"
  22.  
  23. #ifdef MOZILLA_CLIENT
  24.  
  25. #include "mkstream.h"
  26. #include "mkgeturl.h"
  27. #include "xp.h"
  28. #include "zlib.h"
  29.  
  30. extern int MK_OUT_OF_MEMORY;
  31. extern int MK_BAD_GZIP_HEADER;
  32.  
  33. typedef struct _DataObject {
  34.     NET_StreamClass *next_stream;
  35.     z_stream d_stream;  /* decompression stream */
  36.     unsigned char *dcomp_buf;
  37.     uint32 dcomp_buf_size;
  38.     XP_Bool is_done;
  39.     XP_Bool checking_crc_footer;
  40.     unsigned char *incoming_buf;
  41.     uint32 incoming_buf_size;
  42.     XP_Bool header_skipped;
  43.     URL_Struct *URL_s;
  44.     uint32 crc_check;
  45. } DataObject;
  46.  
  47. #define DECOMP_BUF_SIZE NET_Socket_Buffer_Size*2
  48.  
  49. enum check_header_response {
  50.     HEADER_OK,
  51.     BAD_HEADER,
  52.     NEED_MORE_HEADER
  53. };
  54.  
  55. static uint32 gz_magic[2] = {0x1f, 0x8b}; /* gzip magic header */
  56.  
  57. /* gzip flag byte */
  58. #define ASCII_FLAG   0x01 /* bit 0 set: file probably ascii text */
  59. #define HEAD_CRC     0x02 /* bit 1 set: header CRC present */
  60. #define EXTRA_FIELD  0x04 /* bit 2 set: extra field present */
  61. #define ORIG_NAME    0x08 /* bit 3 set: original file name present */
  62. #define COMMENT      0x10 /* bit 4 set: file comment present */
  63. #define RESERVED     0xE0 /* bits 5..7: reserved */
  64.  
  65. /* code copied from Zlib please see zlib.h for copyright statement */
  66. /* ===========================================================================
  67.       Check the gzip header of a gz_stream opened for reading. Set the stream
  68.     mode to transparent if the gzip magic header is not present; set s->err
  69.     to Z_DATA_ERROR if the magic header is present but the rest of the header
  70.     is incorrect.
  71.     IN assertion: the stream s has already been created sucessfully;
  72.        s->stream.avail_in is zero for the first time, but may be non-zero
  73.        for concatenated .gz files.
  74. */
  75. static enum check_header_response
  76. check_header(unsigned char *header, uint32 header_length, uint32 *actual_header_size)
  77. {
  78.     int method; /* method byte */
  79.     int flags;  /* flags byte */
  80.     uInt len;
  81.     uint32 c;
  82.     uint32 orig_header_size = header_length;
  83.  
  84.     /* header must be at least 10 bytes */
  85.     if(header_length < 10)
  86.         return NEED_MORE_HEADER;
  87.  
  88.     /* Check the gzip magic header */
  89.     for (len = 0; len < 2; len++) {
  90.         c = (uint32) *header++;
  91.         header_length--;
  92.         if (c != gz_magic[len]) {
  93.             return BAD_HEADER;
  94.         }
  95.     }
  96.     method = *header++;
  97.     header_length--;
  98.     flags = *header++;
  99.     header_length--;
  100.     if (method != Z_DEFLATED || (flags & RESERVED) != 0) {
  101.         return BAD_HEADER;
  102.     }
  103.  
  104.     /* Discard time, xflags and OS code: */
  105.     for (len = 0; len < 6; len++) 
  106.     {
  107.         header++;
  108.         header_length--;
  109.     }
  110.  
  111.     /* OK we now passed the safe 10 byte boundary, we need to check from here
  112.      * on out to make sure we have enough data
  113.      */
  114.  
  115.     if ((flags & EXTRA_FIELD) != 0) { /* skip the extra field */
  116.         if(header_length < 2)
  117.             return NEED_MORE_HEADER;
  118.  
  119.         len  =  (uInt)*header++;
  120.         header_length--;
  121.         len += ((uInt)*header++)<<8;
  122.         header_length--;
  123.  
  124.         /* len is garbage if EOF but the loop below will quit anyway */
  125.  
  126.         if(header_length < len)
  127.             return NEED_MORE_HEADER;
  128.  
  129.         while (len-- != 0) 
  130.         {
  131.             header++;
  132.             header_length--;
  133.         }
  134.     }
  135.     if ((flags & ORIG_NAME) != 0) { /* skip the original file name */
  136.  
  137.         if(header_length < 1)
  138.             return NEED_MORE_HEADER;
  139.  
  140.         while (*header != '\0')
  141.         {
  142.             header++;
  143.             header_length--;
  144.  
  145.             if(header_length == 0)
  146.                 return NEED_MORE_HEADER;
  147.         }
  148.  
  149.         /* skip null byte */
  150.         header++;
  151.         header_length--;
  152.     }
  153.     if ((flags & COMMENT) != 0) {   /* skip the .gz file comment */
  154.  
  155.         if(header_length < 1)
  156.             return NEED_MORE_HEADER;
  157.  
  158.         while (*header != '\0')
  159.         {
  160.             header++;
  161.             header_length--;
  162.  
  163.             if(header_length == 0)
  164.                 return NEED_MORE_HEADER;
  165.         }
  166.  
  167.         /* skip null byte */
  168.         header++;
  169.         header_length--;
  170.  
  171.     }
  172.     if ((flags & HEAD_CRC) != 0) {  /* skip the header crc */
  173.  
  174.         if(header_length < 2)
  175.             return NEED_MORE_HEADER;
  176.  
  177.         for (len = 0; len < 2; len++)
  178.         {
  179.             header++;
  180.             header_length--;
  181.         }           
  182.     }
  183.  
  184.     *actual_header_size = orig_header_size - header_length;
  185.  
  186.     return HEADER_OK;
  187. }
  188.  
  189. PRIVATE int
  190. do_end_crc_check(DataObject *obj)
  191. {
  192.  
  193.     if(obj->incoming_buf_size >= 8)
  194.     {
  195.         uint32 crc_int;
  196.         uint32 size_int;
  197.  
  198.         obj->checking_crc_footer = FALSE;
  199.         obj->is_done = TRUE;
  200.  
  201.         crc_int = (uint32)obj->incoming_buf[0];
  202.         crc_int += (uint32)obj->incoming_buf[1]<<8;
  203.         crc_int += (uint32)obj->incoming_buf[2]<<16;
  204.         crc_int += (uint32)obj->incoming_buf[3]<<24;
  205.  
  206.         size_int = (uint32)obj->incoming_buf[4];
  207.         size_int += (uint32)obj->incoming_buf[5]<<8;
  208.         size_int += (uint32)obj->incoming_buf[6]<<16;
  209.         size_int += (uint32)obj->incoming_buf[7]<<24;
  210.  
  211.         if(obj->crc_check != crc_int
  212.            || obj->d_stream.total_out != size_int)
  213.         {
  214.             /* crc or size checksum failure */
  215.             obj->URL_s->error_msg = NET_ExplainErrorDetails(MK_BAD_GZIP_HEADER);
  216.             return MK_BAD_GZIP_HEADER;
  217.         }
  218.  
  219.         return 1;
  220.     }
  221.  
  222.     return 0; /* need more data */
  223. }
  224.  
  225. PRIVATE int net_UnZipWrite (NET_StreamClass *stream, CONST char* s, int32 l)
  226. {
  227.     int err;
  228.     uint32 prev_total_out;
  229.     uint32 new_data_total_out;
  230.     uint32 input_used_up, input_left_over;
  231.     char * tempPtr = NULL;
  232.     DataObject *obj=stream->data_object;    
  233.     if(obj->is_done) 
  234.     {
  235.         /* multipart gzip? */
  236.         XP_ASSERT(0);
  237.         return (1);
  238.     }
  239.     
  240.     BlockAllocCat(  tempPtr, obj->incoming_buf_size, s, l);
  241.      obj->incoming_buf = (unsigned char*)tempPtr;
  242.  
  243.     if(!obj->incoming_buf)
  244.         return MK_OUT_OF_MEMORY;
  245.     obj->incoming_buf_size += l;
  246.  
  247.     /* parse and skip the header */
  248.     if(!obj->header_skipped)
  249.     {
  250.         uint32 actual_header_size;
  251.         enum check_header_response status;
  252.  
  253.         status = check_header((unsigned char *)obj->incoming_buf, obj->incoming_buf_size, &actual_header_size);
  254.  
  255.         if(status == HEADER_OK)
  256.         {
  257.             /* squash the header */
  258.             obj->incoming_buf_size -= actual_header_size;
  259.             XP_MEMMOVE(obj->incoming_buf, 
  260.                        obj->incoming_buf+actual_header_size, 
  261.                        obj->incoming_buf_size);
  262.  
  263.             obj->header_skipped = TRUE;
  264.         }
  265.         else if(status == BAD_HEADER)
  266.         {
  267.             obj->URL_s->error_msg = NET_ExplainErrorDetails(MK_BAD_GZIP_HEADER);
  268.             return MK_BAD_GZIP_HEADER;
  269.         }
  270.         else if(status == NEED_MORE_HEADER)
  271.         {
  272.             return 1;
  273.         }
  274.         else
  275.         {
  276.             XP_ASSERT(0);
  277.             return 1;
  278.         }
  279.     }
  280.     else if(obj->checking_crc_footer)
  281.     {
  282.         return do_end_crc_check(obj);
  283.     }
  284.  
  285.     obj->d_stream.next_in  = (unsigned char *)obj->incoming_buf;
  286.     obj->d_stream.avail_in = obj->incoming_buf_size;
  287.     obj->d_stream.next_out = (unsigned char *)obj->dcomp_buf;
  288.     obj->d_stream.avail_out = obj->dcomp_buf_size;
  289.  
  290.     if(obj->d_stream.avail_in <= 0)
  291.         return 1;  /* wait for more data */
  292.  
  293.     prev_total_out = obj->d_stream.total_out;
  294.  
  295.     /* need to loop to finish for small output bufs */
  296.     while(1)
  297.     {
  298.         err = inflate(&obj->d_stream, Z_NO_FLUSH);
  299.  
  300.         /* the amount of new uncompressed data is: */
  301.         new_data_total_out = obj->d_stream.total_out - prev_total_out;
  302.  
  303.         if(new_data_total_out > 0)
  304.         {
  305.             obj->crc_check = crc32(obj->crc_check, 
  306.                                    obj->dcomp_buf, 
  307.                                    new_data_total_out);
  308.  
  309.             (*obj->next_stream->put_block)(obj->next_stream, 
  310.                      (char *)  obj->dcomp_buf, 
  311.                        new_data_total_out);
  312.  
  313.             
  314.         }
  315.  
  316.         obj->d_stream.avail_out = obj->dcomp_buf_size;
  317.         obj->d_stream.next_out = (unsigned char *)obj->dcomp_buf;
  318.         prev_total_out = obj->d_stream.total_out;
  319.  
  320.         if(err == Z_STREAM_END)
  321.         {
  322.             obj->checking_crc_footer = TRUE;
  323.             break;
  324.         }
  325.         else if(err != Z_OK)
  326.         {
  327.             /* need to get more data on next pass 
  328.              * @@@ should check for more critical errors
  329.              */
  330.             break;
  331.         }
  332.         else if(obj->d_stream.avail_in <= 0)
  333.         {
  334.             /* need more data */
  335.             break;
  336.         }
  337.  
  338.     }
  339.  
  340.     /* remove the part that has already been decoding from the incoming buf */
  341.     input_left_over = obj->d_stream.avail_in;
  342.  
  343.     if(input_left_over > 0)
  344.     {
  345.         input_used_up = obj->incoming_buf_size - input_left_over; 
  346.         XP_MEMMOVE(obj->incoming_buf, obj->incoming_buf+input_used_up, input_left_over);
  347.         obj->incoming_buf_size = input_left_over;
  348.     }
  349.     else
  350.     {
  351.         obj->incoming_buf_size = 0;
  352.     }
  353.  
  354.     if(obj->checking_crc_footer == TRUE)
  355.     {
  356.         return do_end_crc_check(obj);
  357.     }
  358.  
  359.     return(1);
  360. }
  361.  
  362. /* is the stream ready for writeing?
  363.  */
  364. PRIVATE unsigned int net_UnZipWriteReady (NET_StreamClass * stream)
  365. {
  366.    DataObject *obj=stream->data_object;   
  367.    return((*obj->next_stream->is_write_ready)(obj->next_stream));  /* always ready for writing */ 
  368. }
  369.  
  370.  
  371. PRIVATE void net_UnZipComplete (NET_StreamClass *stream)
  372. {
  373.     DataObject *obj=stream->data_object;
  374.     int err;    
  375.  
  376.     (*obj->next_stream->complete)(obj->next_stream);
  377.  
  378.     err = inflateEnd(&(obj->d_stream));
  379.     XP_ASSERT(err == Z_OK);
  380.  
  381.     if(!obj->is_done)
  382.     {
  383.         /* we didn't complete the crc and size checks */
  384.         /* @@@ not sure what to do here yet */
  385.         XP_ASSERT(0);
  386.     }
  387.  
  388.     FREE(obj->dcomp_buf);
  389.     FREE(obj);
  390.     return;
  391. }
  392.  
  393. PRIVATE void net_UnZipAbort (NET_StreamClass *stream, int status)
  394. {
  395.     DataObject *obj=stream->data_object;
  396.     int err;    
  397.  
  398.     (*obj->next_stream->abort)(obj->next_stream, status);
  399.  
  400.     err = inflateEnd(&(obj->d_stream));
  401.     XP_ASSERT(err == Z_OK);
  402.  
  403.     FREE(obj->dcomp_buf);
  404.     FREE(obj);
  405.     return;
  406. }
  407.  
  408.  
  409. PUBLIC NET_StreamClass * 
  410. NET_UnZipConverter (int         format_out,
  411.                          void       *data_obj,
  412.                          URL_Struct *URL_s,
  413.                          MWContext  *window_id)
  414. {
  415.     DataObject* obj;
  416.     NET_StreamClass* stream;
  417.     int err;
  418.     
  419.     TRACEMSG(("Setting up display stream. Have URL: %s\n", URL_s->address));
  420.  
  421.     stream = XP_NEW(NET_StreamClass);
  422.     if(stream == NULL) 
  423.         return(NULL);
  424.  
  425.     obj = XP_NEW_ZAP(DataObject);
  426.     if (obj == NULL) 
  427.     {
  428.         FREE(stream);
  429.         return(NULL);
  430.     }
  431.     
  432.     stream->name           = "UnZiper";
  433.     stream->complete       = (MKStreamCompleteFunc) net_UnZipComplete;
  434.     stream->abort          = (MKStreamAbortFunc) net_UnZipAbort;
  435.     stream->put_block      = (MKStreamWriteFunc) net_UnZipWrite;
  436.     stream->is_write_ready = (MKStreamWriteReadyFunc) net_UnZipWriteReady;
  437.     stream->data_object    = obj;  /* document info object */
  438.     stream->window_id      = window_id;
  439.  
  440.     obj->dcomp_buf = XP_ALLOC(DECOMP_BUF_SIZE);
  441.     obj->dcomp_buf_size = DECOMP_BUF_SIZE;
  442.  
  443.     if(!obj->dcomp_buf)
  444.     {
  445.     FREE(stream);
  446.     FREE(obj);
  447.     return NULL;
  448.     }
  449.  
  450.     obj->URL_s = URL_s;
  451.  
  452.     obj->d_stream.zalloc = (alloc_func)0;
  453.     obj->d_stream.zfree = (free_func)0;
  454.     obj->d_stream.opaque = (voidpf)0;
  455.  
  456.     err = inflateInit2(&obj->d_stream, -15);
  457.  
  458.     if(err != Z_OK)
  459.     {
  460.     FREE(stream);
  461.     FREE(obj);
  462.     return NULL;
  463.     }
  464.  
  465.     /* create the next stream, but strip the compressed encoding */
  466.     FREE_AND_CLEAR(URL_s->content_encoding);
  467.     obj->next_stream = NET_StreamBuilder(format_out, URL_s, window_id);
  468.  
  469.     if(!obj->next_stream)
  470.     {
  471.     inflateEnd(&obj->d_stream);
  472.     FREE(stream);
  473.     FREE(obj);
  474.     return NULL;
  475.     }
  476.  
  477.     TRACEMSG(("Returning stream from NET_UnZipConverter\n"));
  478.  
  479.     return stream;
  480. }
  481.  
  482. #endif /* MOZILLA_CLIENT */
  483.