зеркало из https://github.com/mozilla/gecko-dev.git
in order to make libmime compile without libmsg, moved some
utility functions from libmsg/msgutil.c to new files libxp/xp_linebuf.c and libnet/mkbuf.c: msg_GrowBuffer ==> XP_GrowBuffer msg_LineBuffer ==> XP_LineBuffer msg_ReBuffer ==> XP_ReBuffer msg_MakeRebufferingStream ==> NET_MakeRebufferingStream
This commit is contained in:
Родитель
8ec2164a59
Коммит
4e53d461b5
|
@ -32,7 +32,7 @@
|
|||
lib/xp/xp_str.o, and lib/libmsg/addr.o, because those files *actually
|
||||
stand on their own*!
|
||||
|
||||
Life kinda s#$%s, but oh well.
|
||||
Life kinda sucks, but oh well.
|
||||
*/
|
||||
|
||||
#include "xp.h"
|
||||
|
@ -636,40 +636,6 @@ NET_Escape (const char * str, int mask)
|
|||
}
|
||||
|
||||
|
||||
/* from libmsg/msgutils.c */
|
||||
int
|
||||
msg_GrowBuffer (uint32 desired_size, uint32 element_size, uint32 quantum,
|
||||
char **buffer, uint32 *size)
|
||||
{
|
||||
if (*size <= desired_size)
|
||||
{
|
||||
char *new_buf;
|
||||
uint32 increment = desired_size - *size;
|
||||
if (increment < quantum) /* always grow by a minimum of N bytes */
|
||||
increment = quantum;
|
||||
|
||||
#ifdef TESTFORWIN16
|
||||
if (((*size + increment) * (element_size / sizeof(char))) >= 64000)
|
||||
{
|
||||
/* Make sure we don't choke on WIN16 */
|
||||
XP_ASSERT(0);
|
||||
return MK_OUT_OF_MEMORY;
|
||||
}
|
||||
#endif /* DEBUG */
|
||||
|
||||
new_buf = (*buffer
|
||||
? (char *) XP_REALLOC (*buffer, (*size + increment)
|
||||
* (element_size / sizeof(char)))
|
||||
: (char *) XP_ALLOC ((*size + increment)
|
||||
* (element_size / sizeof(char))));
|
||||
if (! new_buf)
|
||||
return MK_OUT_OF_MEMORY;
|
||||
*buffer = new_buf;
|
||||
*size += increment;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
XP_List * ExternalURLTypeList=0;
|
||||
|
||||
|
@ -1146,99 +1112,3 @@ msg_convert_and_send_buffer(char* buf, int length, XP_Bool convert_newlines_p,
|
|||
|
||||
return (*per_line_fn)(buf, length, closure);
|
||||
}
|
||||
|
||||
|
||||
/* from libmsg/msgutils.c */
|
||||
int
|
||||
msg_LineBuffer (const char *net_buffer, int32 net_buffer_size,
|
||||
char **bufferP, uint32 *buffer_sizeP, uint32 *buffer_fpP,
|
||||
XP_Bool convert_newlines_p,
|
||||
int32 (*per_line_fn) (char *line, uint32 line_length,
|
||||
void *closure),
|
||||
void *closure)
|
||||
{
|
||||
int status = 0;
|
||||
if (*buffer_fpP > 0 && *bufferP && (*bufferP)[*buffer_fpP - 1] == CR &&
|
||||
net_buffer_size > 0 && net_buffer[0] != LF) {
|
||||
/* The last buffer ended with a CR. The new buffer does not start
|
||||
with a LF. This old buffer should be shipped out and discarded. */
|
||||
XP_ASSERT(*buffer_sizeP > *buffer_fpP);
|
||||
if (*buffer_sizeP <= *buffer_fpP) return -1;
|
||||
status = msg_convert_and_send_buffer(*bufferP, *buffer_fpP,
|
||||
convert_newlines_p,
|
||||
per_line_fn, closure);
|
||||
if (status < 0) return status;
|
||||
*buffer_fpP = 0;
|
||||
}
|
||||
while (net_buffer_size > 0)
|
||||
{
|
||||
const char *net_buffer_end = net_buffer + net_buffer_size;
|
||||
const char *newline = 0;
|
||||
const char *s;
|
||||
|
||||
|
||||
for (s = net_buffer; s < net_buffer_end; s++)
|
||||
{
|
||||
/* Move forward in the buffer until the first newline.
|
||||
Stop when we see CRLF, CR, or LF, or the end of the buffer.
|
||||
*But*, if we see a lone CR at the *very end* of the buffer,
|
||||
treat this as if we had reached the end of the buffer without
|
||||
seeing a line terminator. This is to catch the case of the
|
||||
buffers splitting a CRLF pair, as in "FOO\r\nBAR\r" "\nBAZ\r\n".
|
||||
*/
|
||||
if (*s == CR || *s == LF)
|
||||
{
|
||||
newline = s;
|
||||
if (newline[0] == CR)
|
||||
{
|
||||
if (s == net_buffer_end - 1)
|
||||
{
|
||||
/* CR at end - wait for the next character. */
|
||||
newline = 0;
|
||||
break;
|
||||
}
|
||||
else if (newline[1] == LF)
|
||||
/* CRLF seen; swallow both. */
|
||||
newline++;
|
||||
}
|
||||
newline++;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* Ensure room in the net_buffer and append some or all of the current
|
||||
chunk of data to it. */
|
||||
{
|
||||
const char *end = (newline ? newline : net_buffer_end);
|
||||
uint32 desired_size = (end - net_buffer) + (*buffer_fpP) + 1;
|
||||
|
||||
if (desired_size >= (*buffer_sizeP))
|
||||
{
|
||||
status = msg_GrowBuffer (desired_size, sizeof(char), 1024,
|
||||
bufferP, buffer_sizeP);
|
||||
if (status < 0) return status;
|
||||
}
|
||||
XP_MEMCPY ((*bufferP) + (*buffer_fpP), net_buffer, (end - net_buffer));
|
||||
(*buffer_fpP) += (end - net_buffer);
|
||||
}
|
||||
|
||||
/* Now *bufferP contains either a complete line, or as complete
|
||||
a line as we have read so far.
|
||||
|
||||
If we have a line, process it, and then remove it from `*bufferP'.
|
||||
Then go around the loop again, until we drain the incoming data.
|
||||
*/
|
||||
if (!newline)
|
||||
return 0;
|
||||
|
||||
status = msg_convert_and_send_buffer(*bufferP, *buffer_fpP,
|
||||
convert_newlines_p,
|
||||
per_line_fn, closure);
|
||||
if (status < 0) return status;
|
||||
|
||||
net_buffer_size -= (newline - net_buffer);
|
||||
net_buffer = newline;
|
||||
(*buffer_fpP) = 0;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -79,379 +79,6 @@ msg_InterruptContext(MWContext* context, XP_Bool safetoo)
|
|||
}
|
||||
|
||||
|
||||
/* Buffer management.
|
||||
Why do I feel like I've written this a hundred times before?
|
||||
*/
|
||||
int
|
||||
msg_GrowBuffer (uint32 desired_size, uint32 element_size, uint32 quantum,
|
||||
char **buffer, uint32 *size)
|
||||
{
|
||||
if (*size <= desired_size)
|
||||
{
|
||||
char *new_buf;
|
||||
uint32 increment = desired_size - *size;
|
||||
if (increment < quantum) /* always grow by a minimum of N bytes */
|
||||
increment = quantum;
|
||||
|
||||
#ifdef TESTFORWIN16
|
||||
if (((*size + increment) * (element_size / sizeof(char))) >= 64000)
|
||||
{
|
||||
/* Be safe on WIN16 */
|
||||
XP_ASSERT(0);
|
||||
return MK_OUT_OF_MEMORY;
|
||||
}
|
||||
#endif /* DEBUG */
|
||||
|
||||
new_buf = (*buffer
|
||||
? (char *) XP_REALLOC (*buffer, (*size + increment)
|
||||
* (element_size / sizeof(char)))
|
||||
: (char *) XP_ALLOC ((*size + increment)
|
||||
* (element_size / sizeof(char))));
|
||||
if (! new_buf)
|
||||
return MK_OUT_OF_MEMORY;
|
||||
*buffer = new_buf;
|
||||
*size += increment;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
extern XP_Bool NET_POP3TooEarlyForEnd(int32 len);
|
||||
|
||||
/* Take the given buffer, tweak the newlines at the end if necessary, and
|
||||
send it off to the given routine. We are guaranteed that the given
|
||||
buffer has allocated space for at least one more character at the end. */
|
||||
static int
|
||||
msg_convert_and_send_buffer(char* buf, uint32 length, XP_Bool convert_newlines_p,
|
||||
int32 (*per_line_fn) (char *line,
|
||||
uint32 line_length,
|
||||
void *closure),
|
||||
void *closure)
|
||||
{
|
||||
/* Convert the line terminator to the native form.
|
||||
*/
|
||||
char* newline;
|
||||
|
||||
XP_ASSERT(buf && length > 0);
|
||||
if (!buf || length <= 0) return -1;
|
||||
newline = buf + length;
|
||||
|
||||
XP_ASSERT(newline[-1] == CR || newline[-1] == LF);
|
||||
if (newline[-1] != CR && newline[-1] != LF) return -1;
|
||||
|
||||
NET_POP3TooEarlyForEnd(length); /* update count of bytes parsed adding/removing CR or LF*/
|
||||
|
||||
if (!convert_newlines_p)
|
||||
{
|
||||
}
|
||||
#if (LINEBREAK_LEN == 1)
|
||||
else if ((newline - buf) >= 2 &&
|
||||
newline[-2] == CR &&
|
||||
newline[-1] == LF)
|
||||
{
|
||||
/* CRLF -> CR or LF */
|
||||
buf [length - 2] = LINEBREAK[0];
|
||||
length--;
|
||||
}
|
||||
else if (newline > buf + 1 &&
|
||||
newline[-1] != LINEBREAK[0])
|
||||
{
|
||||
/* CR -> LF or LF -> CR */
|
||||
buf [length - 1] = LINEBREAK[0];
|
||||
}
|
||||
#else
|
||||
else if (((newline - buf) >= 2 && newline[-2] != CR) ||
|
||||
((newline - buf) >= 1 && newline[-1] != LF))
|
||||
{
|
||||
/* LF -> CRLF or CR -> CRLF */
|
||||
length++;
|
||||
buf[length - 2] = LINEBREAK[0];
|
||||
buf[length - 1] = LINEBREAK[1];
|
||||
}
|
||||
#endif
|
||||
|
||||
return (*per_line_fn)(buf, length, closure);
|
||||
}
|
||||
|
||||
|
||||
/* SI::BUFFERED-STREAM-MIXIN
|
||||
Why do I feel like I've written this a hundred times before?
|
||||
*/
|
||||
|
||||
|
||||
int
|
||||
msg_LineBuffer (const char *net_buffer, int32 net_buffer_size,
|
||||
char **bufferP, uint32 *buffer_sizeP, uint32 *buffer_fpP,
|
||||
XP_Bool convert_newlines_p,
|
||||
int32 (*per_line_fn) (char *line, uint32 line_length,
|
||||
void *closure),
|
||||
void *closure)
|
||||
{
|
||||
int status = 0;
|
||||
if (*buffer_fpP > 0 && *bufferP && (*bufferP)[*buffer_fpP - 1] == CR &&
|
||||
net_buffer_size > 0 && net_buffer[0] != LF) {
|
||||
/* The last buffer ended with a CR. The new buffer does not start
|
||||
with a LF. This old buffer should be shipped out and discarded. */
|
||||
XP_ASSERT(*buffer_sizeP > *buffer_fpP);
|
||||
if (*buffer_sizeP <= *buffer_fpP) return -1;
|
||||
status = msg_convert_and_send_buffer(*bufferP, *buffer_fpP,
|
||||
convert_newlines_p,
|
||||
per_line_fn, closure);
|
||||
if (status < 0) return status;
|
||||
*buffer_fpP = 0;
|
||||
}
|
||||
while (net_buffer_size > 0)
|
||||
{
|
||||
const char *net_buffer_end = net_buffer + net_buffer_size;
|
||||
const char *newline = 0;
|
||||
const char *s;
|
||||
|
||||
|
||||
for (s = net_buffer; s < net_buffer_end; s++)
|
||||
{
|
||||
/* Move forward in the buffer until the first newline.
|
||||
Stop when we see CRLF, CR, or LF, or the end of the buffer.
|
||||
*But*, if we see a lone CR at the *very end* of the buffer,
|
||||
treat this as if we had reached the end of the buffer without
|
||||
seeing a line terminator. This is to catch the case of the
|
||||
buffers splitting a CRLF pair, as in "FOO\r\nBAR\r" "\nBAZ\r\n".
|
||||
*/
|
||||
if (*s == CR || *s == LF)
|
||||
{
|
||||
newline = s;
|
||||
if (newline[0] == CR)
|
||||
{
|
||||
if (s == net_buffer_end - 1)
|
||||
{
|
||||
/* CR at end - wait for the next character. */
|
||||
newline = 0;
|
||||
break;
|
||||
}
|
||||
else if (newline[1] == LF)
|
||||
/* CRLF seen; swallow both. */
|
||||
newline++;
|
||||
}
|
||||
newline++;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* Ensure room in the net_buffer and append some or all of the current
|
||||
chunk of data to it. */
|
||||
{
|
||||
const char *end = (newline ? newline : net_buffer_end);
|
||||
uint32 desired_size = (end - net_buffer) + (*buffer_fpP) + 1;
|
||||
|
||||
if (desired_size >= (*buffer_sizeP))
|
||||
{
|
||||
status = msg_GrowBuffer (desired_size, sizeof(char), 1024,
|
||||
bufferP, buffer_sizeP);
|
||||
if (status < 0) return status;
|
||||
}
|
||||
XP_MEMCPY ((*bufferP) + (*buffer_fpP), net_buffer, (end - net_buffer));
|
||||
(*buffer_fpP) += (end - net_buffer);
|
||||
}
|
||||
|
||||
/* Now *bufferP contains either a complete line, or as complete
|
||||
a line as we have read so far.
|
||||
|
||||
If we have a line, process it, and then remove it from `*bufferP'.
|
||||
Then go around the loop again, until we drain the incoming data.
|
||||
*/
|
||||
if (!newline)
|
||||
return 0;
|
||||
|
||||
status = msg_convert_and_send_buffer(*bufferP, *buffer_fpP,
|
||||
convert_newlines_p,
|
||||
per_line_fn, closure);
|
||||
if (status < 0) return status;
|
||||
|
||||
net_buffer_size -= (newline - net_buffer);
|
||||
net_buffer = newline;
|
||||
(*buffer_fpP) = 0;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/* The opposite of msg_LineBuffer(): takes small buffers and packs them
|
||||
up into bigger buffers before passing them along.
|
||||
|
||||
Pass in a desired_buffer_size 0 to tell it to flush (for example, in
|
||||
in the very last call to this function.)
|
||||
*/
|
||||
int
|
||||
msg_ReBuffer (const char *net_buffer, int32 net_buffer_size,
|
||||
uint32 desired_buffer_size,
|
||||
char **bufferP, uint32 *buffer_sizeP, uint32 *buffer_fpP,
|
||||
int32 (*per_buffer_fn) (char *buffer, uint32 buffer_size,
|
||||
void *closure),
|
||||
void *closure)
|
||||
{
|
||||
int status = 0;
|
||||
|
||||
if (desired_buffer_size >= (*buffer_sizeP))
|
||||
{
|
||||
status = msg_GrowBuffer (desired_buffer_size, sizeof(char), 1024,
|
||||
bufferP, buffer_sizeP);
|
||||
if (status < 0) return status;
|
||||
}
|
||||
|
||||
do
|
||||
{
|
||||
int32 size = *buffer_sizeP - *buffer_fpP;
|
||||
if (size > net_buffer_size)
|
||||
size = net_buffer_size;
|
||||
if (size > 0)
|
||||
{
|
||||
XP_MEMCPY ((*bufferP) + (*buffer_fpP), net_buffer, size);
|
||||
(*buffer_fpP) += size;
|
||||
net_buffer += size;
|
||||
net_buffer_size -= size;
|
||||
}
|
||||
|
||||
if (*buffer_fpP > 0 &&
|
||||
*buffer_fpP >= desired_buffer_size)
|
||||
{
|
||||
status = (*per_buffer_fn) ((*bufferP), (*buffer_fpP), closure);
|
||||
*buffer_fpP = 0;
|
||||
if (status < 0) return status;
|
||||
}
|
||||
}
|
||||
while (net_buffer_size > 0);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
struct msg_rebuffering_stream_data
|
||||
{
|
||||
uint32 desired_size;
|
||||
char *buffer;
|
||||
uint32 buffer_size;
|
||||
uint32 buffer_fp;
|
||||
NET_StreamClass *next_stream;
|
||||
};
|
||||
|
||||
|
||||
static int32
|
||||
msg_rebuffering_stream_write_next_chunk (char *buffer, uint32 buffer_size,
|
||||
void *closure)
|
||||
{
|
||||
struct msg_rebuffering_stream_data *sd =
|
||||
(struct msg_rebuffering_stream_data *) closure;
|
||||
XP_ASSERT (sd);
|
||||
if (!sd) return -1;
|
||||
if (!sd->next_stream) return -1;
|
||||
return (*sd->next_stream->put_block) (sd->next_stream,
|
||||
buffer, buffer_size);
|
||||
}
|
||||
|
||||
static int
|
||||
msg_rebuffering_stream_write_chunk (NET_StreamClass *stream,
|
||||
const char* net_buffer,
|
||||
int32 net_buffer_size)
|
||||
{
|
||||
struct msg_rebuffering_stream_data *sd =
|
||||
(struct msg_rebuffering_stream_data *) stream->data_object;
|
||||
XP_ASSERT (sd);
|
||||
if (!sd) return -1;
|
||||
return msg_ReBuffer (net_buffer, net_buffer_size,
|
||||
sd->desired_size,
|
||||
&sd->buffer, &sd->buffer_size, &sd->buffer_fp,
|
||||
msg_rebuffering_stream_write_next_chunk,
|
||||
sd);
|
||||
}
|
||||
|
||||
|
||||
extern XP_Bool ValidateDocData(MWContext *window_id);
|
||||
|
||||
static void
|
||||
msg_rebuffering_stream_abort (NET_StreamClass *stream, int status)
|
||||
{
|
||||
struct msg_rebuffering_stream_data *sd =
|
||||
(struct msg_rebuffering_stream_data *) stream->data_object;
|
||||
if (!sd) return;
|
||||
FREEIF (sd->buffer);
|
||||
if (sd->next_stream)
|
||||
{
|
||||
if (ValidateDocData(sd->next_stream->window_id)) /* otherwise doc_data is gone ! */
|
||||
(*sd->next_stream->abort) (sd->next_stream, status);
|
||||
XP_FREE (sd->next_stream);
|
||||
}
|
||||
XP_FREE (sd);
|
||||
}
|
||||
|
||||
static void
|
||||
msg_rebuffering_stream_complete (NET_StreamClass *stream)
|
||||
{
|
||||
struct msg_rebuffering_stream_data *sd =
|
||||
(struct msg_rebuffering_stream_data *) stream->data_object;
|
||||
if (!sd) return;
|
||||
sd->desired_size = 0;
|
||||
msg_rebuffering_stream_write_chunk (stream, "", 0);
|
||||
FREEIF (sd->buffer);
|
||||
if (sd->next_stream)
|
||||
{
|
||||
(*sd->next_stream->complete) (sd->next_stream);
|
||||
XP_FREE (sd->next_stream);
|
||||
}
|
||||
XP_FREE (sd);
|
||||
}
|
||||
|
||||
static unsigned int
|
||||
msg_rebuffering_stream_write_ready (NET_StreamClass *stream)
|
||||
{
|
||||
struct msg_rebuffering_stream_data *sd =
|
||||
(struct msg_rebuffering_stream_data *) stream->data_object;
|
||||
if (sd && sd->next_stream)
|
||||
return ((*sd->next_stream->is_write_ready)
|
||||
(sd->next_stream));
|
||||
else
|
||||
return (MAX_WRITE_READY);
|
||||
}
|
||||
|
||||
NET_StreamClass *
|
||||
msg_MakeRebufferingStream (NET_StreamClass *next_stream,
|
||||
URL_Struct *url,
|
||||
MWContext *context)
|
||||
{
|
||||
NET_StreamClass *stream;
|
||||
struct msg_rebuffering_stream_data *sd;
|
||||
|
||||
XP_ASSERT (next_stream);
|
||||
|
||||
TRACEMSG(("Setting up rebuffering stream. Have URL: %s\n", url->address));
|
||||
|
||||
stream = XP_NEW (NET_StreamClass);
|
||||
if (!stream) return 0;
|
||||
|
||||
sd = XP_NEW (struct msg_rebuffering_stream_data);
|
||||
if (! sd)
|
||||
{
|
||||
XP_FREE (stream);
|
||||
return 0;
|
||||
}
|
||||
|
||||
XP_MEMSET (sd, 0, sizeof(*sd));
|
||||
XP_MEMSET (stream, 0, sizeof(*stream));
|
||||
|
||||
sd->next_stream = next_stream;
|
||||
sd->desired_size = 10240;
|
||||
|
||||
stream->name = "ReBuffering Stream";
|
||||
stream->complete = msg_rebuffering_stream_complete;
|
||||
stream->abort = msg_rebuffering_stream_abort;
|
||||
stream->put_block = msg_rebuffering_stream_write_chunk;
|
||||
stream->is_write_ready = msg_rebuffering_stream_write_ready;
|
||||
stream->data_object = sd;
|
||||
stream->window_id = context;
|
||||
|
||||
return stream;
|
||||
}
|
||||
|
||||
|
||||
|
||||
XP_Bool
|
||||
MSG_RequiresComposeWindow (const char *url)
|
||||
{
|
||||
|
|
|
@ -41,6 +41,7 @@ CSRCS = \
|
|||
xp_wrap.c \
|
||||
xpassert.c \
|
||||
xplocale.c \
|
||||
xp_linebuf.c \
|
||||
$(NULL)
|
||||
else
|
||||
CSRCS = xp_stub.c
|
||||
|
@ -53,6 +54,9 @@ CSRCS += \
|
|||
allxpstr.c \
|
||||
$(NULL)
|
||||
|
||||
EXPORTS=xp_linebuf.h
|
||||
|
||||
|
||||
REQUIRES = js nspr dbm security img util jtools layer java lay style pref rdf privacy
|
||||
|
||||
ifeq ($(STAND_ALONE_JAVA),1)
|
||||
|
|
|
@ -0,0 +1,308 @@
|
|||
/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*-
|
||||
*
|
||||
* The contents of this file are subject to the Netscape Public License
|
||||
* Version 1.0 (the "License"); you may not use this file except in
|
||||
* compliance with the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/NPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS"
|
||||
* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
|
||||
* the License for the specific language governing rights and limitations
|
||||
* under the License.
|
||||
*
|
||||
* The Original Code is Mozilla Communicator client code.
|
||||
*
|
||||
* The Initial Developer of the Original Code is Netscape Communications
|
||||
* Corporation. Portions created by Netscape are Copyright (C) 1998
|
||||
* Netscape Communications Corporation. All Rights Reserved.
|
||||
*/
|
||||
|
||||
|
||||
/* xp_linebuf.c -- general line-buffering and de-buffering of text streams.
|
||||
Used by libmime, llibmsg, and others.
|
||||
|
||||
This stuff used to be in libmsg/msgutils.c, but it's really not
|
||||
mail-specific. And I had to move it to get libmime to work in the
|
||||
absence of libmsg, so in the meantime, I changed the prefix from MSG_
|
||||
to XP_.
|
||||
*/
|
||||
|
||||
#include "xp_mcom.h"
|
||||
#include "xp_linebuf.h"
|
||||
|
||||
extern int MK_OUT_OF_MEMORY;
|
||||
|
||||
|
||||
/* Amazingly enough, these seem only to be defined in fe_proto.h, which is
|
||||
totally the wrong thing to be including here.
|
||||
*/
|
||||
#define CR '\015'
|
||||
#define LF '\012'
|
||||
#define CRLF "\015\012"
|
||||
|
||||
#ifdef XP_MAC
|
||||
# define LINEBREAK "\012"
|
||||
# define LINEBREAK_LEN 1
|
||||
#else
|
||||
# if defined(XP_WIN) || defined(XP_OS2)
|
||||
# define LINEBREAK "\015\012"
|
||||
# define LINEBREAK_LEN 2
|
||||
# else
|
||||
# ifdef XP_UNIX
|
||||
# define LINEBREAK "\012"
|
||||
# define LINEBREAK_LEN 1
|
||||
# endif /* XP_UNIX */
|
||||
# endif /* XP_WIN */
|
||||
#endif /* XP_MAC */
|
||||
|
||||
|
||||
|
||||
/* Buffer management.
|
||||
Why do I feel like I've written this a hundred times before?
|
||||
*/
|
||||
int
|
||||
XP_GrowBuffer (uint32 desired_size, uint32 element_size, uint32 quantum,
|
||||
char **buffer, uint32 *size)
|
||||
{
|
||||
if (*size <= desired_size)
|
||||
{
|
||||
char *new_buf;
|
||||
uint32 increment = desired_size - *size;
|
||||
if (increment < quantum) /* always grow by a minimum of N bytes */
|
||||
increment = quantum;
|
||||
|
||||
#ifdef TESTFORWIN16
|
||||
if (((*size + increment) * (element_size / sizeof(char))) >= 64000)
|
||||
{
|
||||
/* Be safe on WIN16 */
|
||||
XP_ASSERT(0);
|
||||
return MK_OUT_OF_MEMORY;
|
||||
}
|
||||
#endif /* DEBUG */
|
||||
|
||||
new_buf = (*buffer
|
||||
? (char *) XP_REALLOC (*buffer, (*size + increment)
|
||||
* (element_size / sizeof(char)))
|
||||
: (char *) XP_ALLOC ((*size + increment)
|
||||
* (element_size / sizeof(char))));
|
||||
if (! new_buf)
|
||||
return MK_OUT_OF_MEMORY;
|
||||
*buffer = new_buf;
|
||||
*size += increment;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
#if 0 /* #### what is this?? and what is it doing here?? */
|
||||
extern XP_Bool NET_POP3TooEarlyForEnd(int32 len);
|
||||
#endif
|
||||
|
||||
/* Take the given buffer, tweak the newlines at the end if necessary, and
|
||||
send it off to the given routine. We are guaranteed that the given
|
||||
buffer has allocated space for at least one more character at the end. */
|
||||
static int
|
||||
xp_convert_and_send_buffer(char* buf, uint32 length,
|
||||
XP_Bool convert_newlines_p,
|
||||
int32 (*per_line_fn) (char *line,
|
||||
uint32 line_length,
|
||||
void *closure),
|
||||
void *closure)
|
||||
{
|
||||
/* Convert the line terminator to the native form.
|
||||
*/
|
||||
char* newline;
|
||||
|
||||
XP_ASSERT(buf && length > 0);
|
||||
if (!buf || length <= 0) return -1;
|
||||
newline = buf + length;
|
||||
|
||||
XP_ASSERT(newline[-1] == CR || newline[-1] == LF);
|
||||
if (newline[-1] != CR && newline[-1] != LF) return -1;
|
||||
|
||||
/* update count of bytes parsed adding/removing CR or LF */
|
||||
#if 0 /* #### what is this?? and what is it doing here?? */
|
||||
NET_POP3TooEarlyForEnd(length);
|
||||
#endif
|
||||
|
||||
if (!convert_newlines_p)
|
||||
{
|
||||
}
|
||||
#if (LINEBREAK_LEN == 1)
|
||||
else if ((newline - buf) >= 2 &&
|
||||
newline[-2] == CR &&
|
||||
newline[-1] == LF)
|
||||
{
|
||||
/* CRLF -> CR or LF */
|
||||
buf [length - 2] = LINEBREAK[0];
|
||||
length--;
|
||||
}
|
||||
else if (newline > buf + 1 &&
|
||||
newline[-1] != LINEBREAK[0])
|
||||
{
|
||||
/* CR -> LF or LF -> CR */
|
||||
buf [length - 1] = LINEBREAK[0];
|
||||
}
|
||||
#else
|
||||
else if (((newline - buf) >= 2 && newline[-2] != CR) ||
|
||||
((newline - buf) >= 1 && newline[-1] != LF))
|
||||
{
|
||||
/* LF -> CRLF or CR -> CRLF */
|
||||
length++;
|
||||
buf[length - 2] = LINEBREAK[0];
|
||||
buf[length - 1] = LINEBREAK[1];
|
||||
}
|
||||
#endif
|
||||
|
||||
return (*per_line_fn)(buf, length, closure);
|
||||
}
|
||||
|
||||
|
||||
/* SI::BUFFERED-STREAM-MIXIN
|
||||
Why do I feel like I've written this a hundred times before?
|
||||
*/
|
||||
int
|
||||
XP_LineBuffer (const char *net_buffer, int32 net_buffer_size,
|
||||
char **bufferP, uint32 *buffer_sizeP, uint32 *buffer_fpP,
|
||||
XP_Bool convert_newlines_p,
|
||||
int32 (*per_line_fn) (char *line, uint32 line_length,
|
||||
void *closure),
|
||||
void *closure)
|
||||
{
|
||||
int status = 0;
|
||||
if (*buffer_fpP > 0 && *bufferP && (*bufferP)[*buffer_fpP - 1] == CR &&
|
||||
net_buffer_size > 0 && net_buffer[0] != LF) {
|
||||
/* The last buffer ended with a CR. The new buffer does not start
|
||||
with a LF. This old buffer should be shipped out and discarded. */
|
||||
XP_ASSERT(*buffer_sizeP > *buffer_fpP);
|
||||
if (*buffer_sizeP <= *buffer_fpP) return -1;
|
||||
status = xp_convert_and_send_buffer(*bufferP, *buffer_fpP,
|
||||
convert_newlines_p,
|
||||
per_line_fn, closure);
|
||||
if (status < 0) return status;
|
||||
*buffer_fpP = 0;
|
||||
}
|
||||
while (net_buffer_size > 0)
|
||||
{
|
||||
const char *net_buffer_end = net_buffer + net_buffer_size;
|
||||
const char *newline = 0;
|
||||
const char *s;
|
||||
|
||||
|
||||
for (s = net_buffer; s < net_buffer_end; s++)
|
||||
{
|
||||
/* Move forward in the buffer until the first newline.
|
||||
Stop when we see CRLF, CR, or LF, or the end of the buffer.
|
||||
*But*, if we see a lone CR at the *very end* of the buffer,
|
||||
treat this as if we had reached the end of the buffer without
|
||||
seeing a line terminator. This is to catch the case of the
|
||||
buffers splitting a CRLF pair, as in "FOO\r\nBAR\r" "\nBAZ\r\n".
|
||||
*/
|
||||
if (*s == CR || *s == LF)
|
||||
{
|
||||
newline = s;
|
||||
if (newline[0] == CR)
|
||||
{
|
||||
if (s == net_buffer_end - 1)
|
||||
{
|
||||
/* CR at end - wait for the next character. */
|
||||
newline = 0;
|
||||
break;
|
||||
}
|
||||
else if (newline[1] == LF)
|
||||
/* CRLF seen; swallow both. */
|
||||
newline++;
|
||||
}
|
||||
newline++;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* Ensure room in the net_buffer and append some or all of the current
|
||||
chunk of data to it. */
|
||||
{
|
||||
const char *end = (newline ? newline : net_buffer_end);
|
||||
uint32 desired_size = (end - net_buffer) + (*buffer_fpP) + 1;
|
||||
|
||||
if (desired_size >= (*buffer_sizeP))
|
||||
{
|
||||
status = XP_GrowBuffer (desired_size, sizeof(char), 1024,
|
||||
bufferP, buffer_sizeP);
|
||||
if (status < 0) return status;
|
||||
}
|
||||
XP_MEMCPY ((*bufferP) + (*buffer_fpP), net_buffer, (end - net_buffer));
|
||||
(*buffer_fpP) += (end - net_buffer);
|
||||
}
|
||||
|
||||
/* Now *bufferP contains either a complete line, or as complete
|
||||
a line as we have read so far.
|
||||
|
||||
If we have a line, process it, and then remove it from `*bufferP'.
|
||||
Then go around the loop again, until we drain the incoming data.
|
||||
*/
|
||||
if (!newline)
|
||||
return 0;
|
||||
|
||||
status = xp_convert_and_send_buffer(*bufferP, *buffer_fpP,
|
||||
convert_newlines_p,
|
||||
per_line_fn, closure);
|
||||
if (status < 0) return status;
|
||||
|
||||
net_buffer_size -= (newline - net_buffer);
|
||||
net_buffer = newline;
|
||||
(*buffer_fpP) = 0;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/* The opposite of xp_LineBuffer(): takes small buffers and packs them
|
||||
up into bigger buffers before passing them along.
|
||||
|
||||
Pass in a desired_buffer_size 0 to tell it to flush (for example, in
|
||||
in the very last call to this function.)
|
||||
*/
|
||||
int
|
||||
XP_ReBuffer (const char *net_buffer, int32 net_buffer_size,
|
||||
uint32 desired_buffer_size,
|
||||
char **bufferP, uint32 *buffer_sizeP, uint32 *buffer_fpP,
|
||||
int32 (*per_buffer_fn) (char *buffer, uint32 buffer_size,
|
||||
void *closure),
|
||||
void *closure)
|
||||
{
|
||||
int status = 0;
|
||||
|
||||
if (desired_buffer_size >= (*buffer_sizeP))
|
||||
{
|
||||
status = XP_GrowBuffer (desired_buffer_size, sizeof(char), 1024,
|
||||
bufferP, buffer_sizeP);
|
||||
if (status < 0) return status;
|
||||
}
|
||||
|
||||
do
|
||||
{
|
||||
int32 size = *buffer_sizeP - *buffer_fpP;
|
||||
if (size > net_buffer_size)
|
||||
size = net_buffer_size;
|
||||
if (size > 0)
|
||||
{
|
||||
XP_MEMCPY ((*bufferP) + (*buffer_fpP), net_buffer, size);
|
||||
(*buffer_fpP) += size;
|
||||
net_buffer += size;
|
||||
net_buffer_size -= size;
|
||||
}
|
||||
|
||||
if (*buffer_fpP > 0 &&
|
||||
*buffer_fpP >= desired_buffer_size)
|
||||
{
|
||||
status = (*per_buffer_fn) ((*bufferP), (*buffer_fpP), closure);
|
||||
*buffer_fpP = 0;
|
||||
if (status < 0) return status;
|
||||
}
|
||||
}
|
||||
while (net_buffer_size > 0);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
@ -0,0 +1,55 @@
|
|||
/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*-
|
||||
*
|
||||
* The contents of this file are subject to the Netscape Public License
|
||||
* Version 1.0 (the "License"); you may not use this file except in
|
||||
* compliance with the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/NPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS"
|
||||
* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
|
||||
* the License for the specific language governing rights and limitations
|
||||
* under the License.
|
||||
*
|
||||
* The Original Code is Mozilla Communicator client code.
|
||||
*
|
||||
* The Initial Developer of the Original Code is Netscape Communications
|
||||
* Corporation. Portions created by Netscape are Copyright (C) 1998
|
||||
* Netscape Communications Corporation. All Rights Reserved.
|
||||
*/
|
||||
|
||||
|
||||
/* xp_linebuf.h --- general line-buffering and de-buffering of text streams.
|
||||
Created: Jamie Zawinski <jwz@mozilla.org>, 8-Aug-98.
|
||||
*/
|
||||
|
||||
#ifndef __XP_LINEBUF_H__
|
||||
#define __XP_LINEBUF_H__
|
||||
|
||||
#include "xp_core.h"
|
||||
|
||||
XP_BEGIN_PROTOS
|
||||
|
||||
extern int XP_GrowBuffer (uint32 desired_size, uint32 element_size,
|
||||
uint32 quantum, char **buffer, uint32 *size);
|
||||
|
||||
extern int XP_LineBuffer (const char *net_buffer, int32 net_buffer_size,
|
||||
char **bufferP, uint32 *buffer_sizeP,
|
||||
uint32 *buffer_fpP,
|
||||
XP_Bool convert_newlines_p,
|
||||
int32 (*per_line_fn) (char *line,
|
||||
uint32 line_length,
|
||||
void *closure),
|
||||
void *closure);
|
||||
|
||||
extern int XP_ReBuffer (const char *net_buffer, int32 net_buffer_size,
|
||||
uint32 desired_buffer_size,
|
||||
char **bufferP, uint32 *buffer_sizeP,
|
||||
uint32 *buffer_fpP,
|
||||
int32 (*per_buffer_fn) (char *buffer,
|
||||
uint32 buffer_size,
|
||||
void *closure),
|
||||
void *closure);
|
||||
|
||||
XP_END_PROTOS
|
||||
|
||||
#endif /* __XP_LINEBUF_H__ */
|
|
@ -22,13 +22,14 @@ LIBRARY_NAME = netutil
|
|||
|
||||
CSRCS = \
|
||||
mkreg.c \
|
||||
mkbuf.c \
|
||||
$(NULL)
|
||||
|
||||
EXPORTS=mkreg.h
|
||||
EXPORTS=mkreg.h mkbuf.h
|
||||
|
||||
include $(DEPTH)/config/config.mk
|
||||
|
||||
REQUIRES = network
|
||||
REQUIRES = network xp
|
||||
|
||||
include $(DEPTH)/config/rules.mk
|
||||
|
||||
|
|
|
@ -0,0 +1,169 @@
|
|||
/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*-
|
||||
*
|
||||
* The contents of this file are subject to the Netscape Public License
|
||||
* Version 1.0 (the "License"); you may not use this file except in
|
||||
* compliance with the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/NPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS"
|
||||
* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
|
||||
* the License for the specific language governing rights and limitations
|
||||
* under the License.
|
||||
*
|
||||
* The Original Code is Mozilla Communicator client code.
|
||||
*
|
||||
* The Initial Developer of the Original Code is Netscape Communications
|
||||
* Corporation. Portions created by Netscape are Copyright (C) 1998
|
||||
* Netscape Communications Corporation. All Rights Reserved.
|
||||
*/
|
||||
|
||||
|
||||
/* mkbuf.c --- a netlib stream that buffers data before passing it along.
|
||||
This is used by libmime and libmsg to undo the effects of line-buffering,
|
||||
and to pass along larger chunks of data to various stream handlers (e.g.,
|
||||
layout.)
|
||||
|
||||
This stuff used to be in libmsg/msgutils.c, but it's really not
|
||||
mail-specific. And I had to move it to get libmime to work in the
|
||||
absence of libmsg, so in the meantime, I changed the prefix from MSG_
|
||||
to NET_.
|
||||
|
||||
This depends on XP_ReBuffer (xp_linebuf.c) to do its dirty work.
|
||||
|
||||
Created: Jamie Zawinski <jwz@mozilla.org>, 8-Aug-98.
|
||||
*/
|
||||
|
||||
#include "xp_mcom.h"
|
||||
#include "net.h";
|
||||
#include "xp_linebuf.h"
|
||||
#include "mkbuf.h"
|
||||
|
||||
struct net_rebuffering_stream_data
|
||||
{
|
||||
uint32 desired_size;
|
||||
char *buffer;
|
||||
uint32 buffer_size;
|
||||
uint32 buffer_fp;
|
||||
NET_StreamClass *next_stream;
|
||||
};
|
||||
|
||||
#undef FREEIF
|
||||
#define FREEIF(obj) do { if (obj) { XP_FREE (obj); obj = 0; }} while (0)
|
||||
|
||||
|
||||
static int32
|
||||
net_rebuffering_stream_write_next_chunk (char *buffer, uint32 buffer_size,
|
||||
void *closure)
|
||||
{
|
||||
struct net_rebuffering_stream_data *sd =
|
||||
(struct net_rebuffering_stream_data *) closure;
|
||||
XP_ASSERT (sd);
|
||||
if (!sd) return -1;
|
||||
if (!sd->next_stream) return -1;
|
||||
return (*sd->next_stream->put_block) (sd->next_stream,
|
||||
buffer, buffer_size);
|
||||
}
|
||||
|
||||
static int
|
||||
net_rebuffering_stream_write_chunk (NET_StreamClass *stream,
|
||||
const char* net_buffer,
|
||||
int32 net_buffer_size)
|
||||
{
|
||||
struct net_rebuffering_stream_data *sd =
|
||||
(struct net_rebuffering_stream_data *) stream->data_object;
|
||||
XP_ASSERT (sd);
|
||||
if (!sd) return -1;
|
||||
return XP_ReBuffer (net_buffer, net_buffer_size,
|
||||
sd->desired_size,
|
||||
&sd->buffer, &sd->buffer_size, &sd->buffer_fp,
|
||||
net_rebuffering_stream_write_next_chunk,
|
||||
sd);
|
||||
}
|
||||
|
||||
|
||||
extern XP_Bool ValidateDocData(MWContext *window_id);
|
||||
|
||||
static void
|
||||
net_rebuffering_stream_abort (NET_StreamClass *stream, int status)
|
||||
{
|
||||
struct net_rebuffering_stream_data *sd =
|
||||
(struct net_rebuffering_stream_data *) stream->data_object;
|
||||
if (!sd) return;
|
||||
FREEIF (sd->buffer);
|
||||
if (sd->next_stream)
|
||||
{
|
||||
if (ValidateDocData(sd->next_stream->window_id)) /* otherwise doc_data
|
||||
is gone ! */
|
||||
(*sd->next_stream->abort) (sd->next_stream, status);
|
||||
XP_FREE (sd->next_stream);
|
||||
}
|
||||
XP_FREE (sd);
|
||||
}
|
||||
|
||||
static void
|
||||
net_rebuffering_stream_complete (NET_StreamClass *stream)
|
||||
{
|
||||
struct net_rebuffering_stream_data *sd =
|
||||
(struct net_rebuffering_stream_data *) stream->data_object;
|
||||
if (!sd) return;
|
||||
sd->desired_size = 0;
|
||||
net_rebuffering_stream_write_chunk (stream, "", 0);
|
||||
FREEIF (sd->buffer);
|
||||
if (sd->next_stream)
|
||||
{
|
||||
(*sd->next_stream->complete) (sd->next_stream);
|
||||
XP_FREE (sd->next_stream);
|
||||
}
|
||||
XP_FREE (sd);
|
||||
}
|
||||
|
||||
static unsigned int
|
||||
net_rebuffering_stream_write_ready (NET_StreamClass *stream)
|
||||
{
|
||||
struct net_rebuffering_stream_data *sd =
|
||||
(struct net_rebuffering_stream_data *) stream->data_object;
|
||||
if (sd && sd->next_stream)
|
||||
return ((*sd->next_stream->is_write_ready)
|
||||
(sd->next_stream));
|
||||
else
|
||||
return (MAX_WRITE_READY);
|
||||
}
|
||||
|
||||
NET_StreamClass *
|
||||
NET_MakeRebufferingStream (NET_StreamClass *next_stream,
|
||||
URL_Struct *url,
|
||||
MWContext *context)
|
||||
{
|
||||
NET_StreamClass *stream;
|
||||
struct net_rebuffering_stream_data *sd;
|
||||
|
||||
XP_ASSERT (next_stream);
|
||||
|
||||
TRACEMSG(("Setting up rebuffering stream. Have URL: %s\n", url->address));
|
||||
|
||||
stream = XP_NEW (NET_StreamClass);
|
||||
if (!stream) return 0;
|
||||
|
||||
sd = XP_NEW (struct net_rebuffering_stream_data);
|
||||
if (! sd)
|
||||
{
|
||||
XP_FREE (stream);
|
||||
return 0;
|
||||
}
|
||||
|
||||
XP_MEMSET (sd, 0, sizeof(*sd));
|
||||
XP_MEMSET (stream, 0, sizeof(*stream));
|
||||
|
||||
sd->next_stream = next_stream;
|
||||
sd->desired_size = 10240;
|
||||
|
||||
stream->name = "ReBuffering Stream";
|
||||
stream->complete = net_rebuffering_stream_complete;
|
||||
stream->abort = net_rebuffering_stream_abort;
|
||||
stream->put_block = net_rebuffering_stream_write_chunk;
|
||||
stream->is_write_ready = net_rebuffering_stream_write_ready;
|
||||
stream->data_object = sd;
|
||||
stream->window_id = context;
|
||||
|
||||
return stream;
|
||||
}
|
|
@ -0,0 +1,42 @@
|
|||
/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*-
|
||||
*
|
||||
* The contents of this file are subject to the Netscape Public License
|
||||
* Version 1.0 (the "License"); you may not use this file except in
|
||||
* compliance with the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/NPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS"
|
||||
* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
|
||||
* the License for the specific language governing rights and limitations
|
||||
* under the License.
|
||||
*
|
||||
* The Original Code is Mozilla Communicator client code.
|
||||
*
|
||||
* The Initial Developer of the Original Code is Netscape Communications
|
||||
* Corporation. Portions created by Netscape are Copyright (C) 1998
|
||||
* Netscape Communications Corporation. All Rights Reserved.
|
||||
*/
|
||||
|
||||
|
||||
/* mkbuf.h --- a netlib stream that buffers data before passing it along.
|
||||
This is used by libmime and libmsg to undo the effects of line-buffering,
|
||||
and to pass along larger chunks of data to various stream handlers (e.g.,
|
||||
layout.)
|
||||
|
||||
Created: Jamie Zawinski <jwz@mozilla.org>, 8-Aug-98.
|
||||
*/
|
||||
|
||||
#ifndef __MKBUF_H__
|
||||
#define __MKBUF_H__
|
||||
|
||||
#include "ntypes.h"
|
||||
|
||||
XP_BEGIN_PROTOS
|
||||
|
||||
extern NET_StreamClass *NET_MakeRebufferingStream (NET_StreamClass *next,
|
||||
URL_Struct *url,
|
||||
MWContext *context);
|
||||
|
||||
XP_END_PROTOS
|
||||
|
||||
#endif /* __MKBUF_H__ */
|
Загрузка…
Ссылка в новой задаче