home *** CD-ROM | disk | FTP | other *** search
/ Tools / WinSN5.0Ver.iso / NETSCAP.50 / WIN1998.ZIP / ns / lib / libnet / cvchunk.c < prev    next >
Encoding:
C/C++ Source or Header  |  1998-04-08  |  8.8 KB  |  316 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. /* Please leave outside of ifdef for windows precompiled headers */
  19. #include "mkutils.h"
  20.  
  21. #ifdef MOZILLA_CLIENT
  22.  
  23. #include "cvchunk.h"    /* prototype */
  24. #include "mkstream.h"
  25. #include "mkgeturl.h"
  26. #include "xp.h"
  27.  
  28. extern int MK_OUT_OF_MEMORY;
  29.  
  30. typedef enum {
  31.     FIND_CHUNK_SIZE,
  32.     READ_CHUNK,
  33.     STRIP_CRLF,
  34.     PARSE_FOOTER
  35. } States;
  36.  
  37. typedef struct _DataObject {
  38.     NET_StreamClass *next_stream;
  39.     char *in_buf;
  40.     uint32 in_buf_size;
  41.     uint32 chunk_size;
  42.     uint32 amount_of_chunk_parsed;
  43.     States cur_state;
  44.     FO_Present_Types format_out;
  45.     MWContext *context;
  46.     URL_Struct *URL_s;
  47. } DataObject;
  48.  
  49.  
  50. /* unchunk the message and return MK_MULTIPART_MESSAGE_COMPLETED
  51.  * when end detected
  52.  */
  53. PRIVATE int net_ChunkedWrite (NET_StreamClass *stream, char* s, int32 l)
  54. {
  55.     DataObject *obj=stream->data_object;    
  56.     BlockAllocCat(obj->in_buf, obj->in_buf_size, s, l);
  57.     if(!obj->in_buf)
  58.         return MK_OUT_OF_MEMORY;
  59.     obj->in_buf_size += l;
  60.  
  61.     while(obj->in_buf_size > 0)
  62.     {
  63.         if(obj->cur_state == FIND_CHUNK_SIZE)
  64.         {
  65.             char *line_feed;
  66.             char *semicolon;
  67.             char *end;
  68.  
  69.             /* we don't have a current chunk size 
  70.                * look for a new chunk size 
  71.               *
  72.               * make sure the line has a CRLF
  73.                */
  74.             if((line_feed = XP_STRNCHR(obj->in_buf, LF, obj->in_buf_size)) == NULL)
  75.             {
  76.                 return 1;  /* need more data */
  77.             }
  78.             
  79.             *line_feed = '\0';
  80.  
  81.             semicolon = XP_STRNCHR(obj->in_buf, ';', line_feed-obj->in_buf);
  82.  
  83.             if(semicolon)
  84.                 *semicolon = '\0';
  85.  
  86.             end = semicolon ? semicolon : line_feed;
  87.  
  88.             /* read the first integer and ignore any thing
  89.               * else on the line.  Extensions are allowed
  90.               */
  91.             obj->chunk_size = strtol(obj->in_buf, &end, 16);
  92.     
  93.             /* strip everything up to the line feed */
  94.             obj->in_buf_size -= (line_feed+1) - obj->in_buf;
  95.             if(obj->in_buf_size)
  96.                 XP_MEMMOVE(obj->in_buf, 
  97.                            line_feed+1, 
  98.                            obj->in_buf_size);
  99.     
  100.             if(obj->chunk_size == 0)
  101.             {
  102.                 /* the stream should be done now */
  103.                 obj->cur_state = PARSE_FOOTER;
  104.             }
  105.             else
  106.             {
  107.                 obj->cur_state = READ_CHUNK;
  108.             }
  109.  
  110.         }
  111.         else if(obj->cur_state == READ_CHUNK)
  112.         {
  113.             uint32 data_size;
  114.             int32 status;
  115.  
  116.             /* take as much data as we have and push it up the stream
  117.              */
  118.  
  119.             data_size = MIN(obj->in_buf_size, obj->chunk_size-obj->amount_of_chunk_parsed);
  120.  
  121.             status = (obj->next_stream->put_block)(obj->next_stream,
  122.                                                      obj->in_buf,
  123.                                                      data_size);
  124.             if(status < 0)
  125.                 return status;
  126.  
  127.             /* remove the part that has been pushed */
  128.             obj->in_buf_size -= data_size;
  129.             if(obj->in_buf_size)
  130.                 XP_MEMMOVE(obj->in_buf, 
  131.                            obj->in_buf+data_size, 
  132.                            obj->in_buf_size);
  133.  
  134.             obj->amount_of_chunk_parsed += data_size;
  135.     
  136.             if(obj->amount_of_chunk_parsed >= obj->chunk_size)
  137.             {
  138.                 XP_ASSERT(obj->amount_of_chunk_parsed == obj->chunk_size);
  139.                 /* reinit */
  140.                 obj->amount_of_chunk_parsed = 0;
  141.                 obj->cur_state = STRIP_CRLF;
  142.             }
  143.         }
  144.         else if(obj->cur_state == STRIP_CRLF)
  145.         {
  146.             if(obj->in_buf_size > 1 && obj->in_buf[0] == CR && obj->in_buf[1] == LF)
  147.             {
  148.                 /* strip two bytes */ 
  149.                 obj->in_buf_size -= 2;
  150.                 if(obj->in_buf_size)
  151.                     XP_MEMMOVE(obj->in_buf, 
  152.                                obj->in_buf+2, 
  153.                                obj->in_buf_size);
  154.                 obj->cur_state = FIND_CHUNK_SIZE;
  155.             }
  156.             else if(obj->in_buf[0] == LF)
  157.             {
  158.                 /* strip one bytes */ 
  159.                 obj->in_buf_size -= 1;
  160.                 if(obj->in_buf_size)
  161.                     XP_MEMMOVE(obj->in_buf, 
  162.                                obj->in_buf+1, 
  163.                                obj->in_buf_size);
  164.                 obj->cur_state = FIND_CHUNK_SIZE;
  165.             }
  166.             else
  167.             {
  168.                 if(obj->in_buf_size >= 2)
  169.                 {
  170.                     int status;
  171.                     
  172.                     /* a fatal parse error */
  173.                     XP_ASSERT(0);
  174.  
  175.                     /* just spew the buf to the screen */
  176.                        status = (obj->next_stream->put_block)(obj->next_stream,
  177.                                                      obj->in_buf,
  178.                                                      obj->in_buf_size);
  179.                     if(status < 0)
  180.                         return status;
  181.  
  182.                     /* remove the part that has been pushed */
  183.                     obj->in_buf_size = 0;
  184.                 }
  185.             }
  186.         }
  187.         else if(obj->cur_state == PARSE_FOOTER)
  188.         {
  189.             char *line_feed;
  190.             char *value;
  191.  
  192.             /* parse until we see two CRLF's in a row */
  193.             if((line_feed = XP_STRNCHR(obj->in_buf, LF, obj->in_buf_size)) == NULL)
  194.             {
  195.                 return 1;  /* need more data */
  196.             }
  197.  
  198.             *line_feed = '\0';
  199.  
  200.             /* strip the CR */
  201.             if(line_feed != obj->in_buf && *(line_feed-1) == CR)
  202.                 *(line_feed-1) = '\0';
  203.         
  204.             if(*obj->in_buf == '\0')
  205.             {
  206.                 /* end of parse stream */
  207.                 return MK_MULTIPART_MESSAGE_COMPLETED;
  208.             }
  209.  
  210.             /* names are separated from values with a colon
  211.             */
  212.             value = XP_STRCHR(obj->in_buf, ':');
  213.             if(value)
  214.                 value++;
  215.  
  216.             /* otherwise parse the line as a mime header */
  217.             NET_ParseMimeHeader(obj->format_out,
  218.                                 obj->context,
  219.                                 obj->URL_s,
  220.                                 obj->in_buf,
  221.                                 value,
  222.                                 FALSE);
  223.  
  224.             /* strip the line from the buffer */
  225.             obj->in_buf_size -= (line_feed+1) - obj->in_buf;
  226.             if(obj->in_buf_size)
  227.                 XP_MEMMOVE(obj->in_buf, 
  228.                            line_feed+1, 
  229.                            obj->in_buf_size);
  230.         }
  231.     }
  232.     
  233.     XP_ASSERT(obj->in_buf_size == 0);
  234.  
  235.     return(1);
  236. }
  237.  
  238. /* is the stream ready for writeing?
  239.  */
  240. PRIVATE unsigned int net_ChunkedWriteReady (NET_StreamClass * stream)
  241. {
  242.    DataObject *obj=stream->data_object;
  243.    return (*obj->next_stream->is_write_ready)(obj->next_stream);
  244. }
  245.  
  246.  
  247. PRIVATE void net_ChunkedComplete (NET_StreamClass *stream)
  248. {
  249.     DataObject *obj=stream->data_object;    
  250.     (*obj->next_stream->complete)(obj->next_stream);
  251.  
  252.     FREE(obj);
  253.     return;
  254. }
  255.  
  256. PRIVATE void net_ChunkedAbort (NET_StreamClass *stream, int status)
  257. {
  258.     DataObject *obj=stream->data_object;    
  259.     (*obj->next_stream->abort)(obj->next_stream, status);
  260.  
  261.     return;
  262. }
  263.  
  264.  
  265. MODULE_PRIVATE NET_StreamClass * 
  266. NET_ChunkedDecoderStream (int         format_out,
  267.                          void       *data_obj,
  268.                          URL_Struct *URL_s,
  269.                          MWContext  *window_id)
  270. {
  271.     DataObject* obj;
  272.     NET_StreamClass* stream;
  273.     
  274.     TRACEMSG(("Setting up display stream. Have URL: %s\n", URL_s->address));
  275.  
  276.     stream = XP_NEW(NET_StreamClass);
  277.     if(stream == NULL) 
  278.         return(NULL);
  279.  
  280.     obj = XP_NEW_ZAP(DataObject);
  281.     if (obj == NULL) 
  282.         return(NULL);
  283.     
  284.     stream->name           = "Chunked decoder";
  285.     stream->complete       = (MKStreamCompleteFunc) net_ChunkedComplete;
  286.     stream->abort          = (MKStreamAbortFunc) net_ChunkedAbort;
  287.     stream->put_block      = (MKStreamWriteFunc) net_ChunkedWrite;
  288.     stream->is_write_ready = (MKStreamWriteReadyFunc) net_ChunkedWriteReady;
  289.     stream->data_object    = obj;  /* document info object */
  290.     stream->window_id      = window_id;
  291.  
  292.     /* clear the "chunked" encoding */
  293.     if(URL_s->transfer_encoding)
  294.         FREE_AND_CLEAR(URL_s->transfer_encoding);
  295.     else
  296.         FREE_AND_CLEAR(URL_s->content_encoding);
  297.     obj->next_stream = NET_StreamBuilder(format_out, URL_s, window_id);
  298.  
  299.     if(!obj->next_stream)
  300.     {
  301.         XP_FREE(obj);
  302.         XP_FREE(stream);
  303.         return NULL;
  304.     }
  305.  
  306.     obj->context = window_id;
  307.     obj->format_out = format_out;
  308.     obj->URL_s = URL_s;
  309.  
  310.     TRACEMSG(("Returning stream from NET_ChunkedConverter\n"));
  311.  
  312.     return stream;
  313. }
  314.  
  315. #endif /* MOZILLA_CLIENT */
  316.