Compare commits

..

2 Commits

Author SHA1 Message Date
pavlov%netscape.com
c45c2db17b new shit
git-svn-id: svn://10.0.0.236/branches/IMGLIB2_NEW@91713 18797224-902f-48f8-a5cc-f745e15eee43
2001-04-08 23:55:33 +00:00
(no author)
ebc0074860 This commit was manufactured by cvs2svn to create branch 'IMGLIB2_NEW'.
git-svn-id: svn://10.0.0.236/branches/IMGLIB2_NEW@91429 18797224-902f-48f8-a5cc-f745e15eee43
2001-04-05 06:02:33 +00:00
167 changed files with 10309 additions and 185905 deletions

View File

@@ -0,0 +1,33 @@
#
# The contents of this file are subject to the Mozilla Public
# License Version 1.1 (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/MPL/
#
# 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.org code
#
# The Initial Developer of the Original Code is Netscape
# Communications Corporation. Portions created by Netscape are
# Copyright (C) 2001 Netscape Communications Corporation. All
# Rights Reserved.
#
# Contributor(s):
#
DEPTH = ../..
topsrcdir = @top_srcdir@
srcdir = @srcdir@
VPATH = @srcdir@
include $(DEPTH)/config/autoconf.mk
DIRS = public src decoders
include $(topsrcdir)/config/rules.mk

View File

@@ -0,0 +1,32 @@
#
# The contents of this file are subject to the Mozilla Public
# License Version 1.1 (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/MPL/
#
# 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.org code
#
# The Initial Developer of the Original Code is Netscape
# Communications Corporation. Portions created by Netscape are
# Copyright (C) 2001 Netscape Communications Corporation. All
# Rights Reserved.
#
# Contributor(s):
#
DEPTH = ../../..
topsrcdir = @top_srcdir@
srcdir = @srcdir@
VPATH = @srcdir@
include $(DEPTH)/config/autoconf.mk
DIRS = ppm png gif jpeg
include $(topsrcdir)/config/rules.mk

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,323 @@
/* -*- 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.1 (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.
*
* Contributor(s):
*/
#ifndef _GIF_H_
#define _GIF_H_
/* gif2.h
The interface for the GIF87/89a decoder.
*/
// List of possible parsing states
typedef enum {
gif_gather,
gif_init, //1
gif_type,
gif_version,
gif_global_header,
gif_global_colormap,
gif_image_start, //6
gif_image_header,
gif_image_colormap,
gif_image_body,
gif_lzw_start,
gif_lzw, //11
gif_sub_block,
gif_extension,
gif_control_extension,
gif_consume_block,
gif_skip_block,
gif_done, //17
gif_oom,
gif_error,
gif_comment_extension,
gif_application_extension,
gif_netscape_extension_block,
gif_consume_netscape_extension,
gif_consume_comment,
gif_delay,
gif_wait_for_buffer_full,
gif_stop_animating //added for animation stop
} gstate;
/* "Disposal" method indicates how the image should be handled in the
framebuffer before the subsequent image is displayed. */
typedef enum
{
DISPOSE_NOT_SPECIFIED = 0,
DISPOSE_KEEP = 1, /* Leave it in the framebuffer */
DISPOSE_OVERWRITE_BGCOLOR = 2, /* Overwrite with background color */
DISPOSE_OVERWRITE_PREVIOUS = 4 /* Save-under */
} gdispose;
/* A RGB triplet representing a single pixel in the image's colormap
(if present.) */
typedef struct _GIF_RGB
{
PRUint8 red, green, blue, pad; /* Windows requires the fourth byte &
many compilers pad it anyway. */
/* XXX: hist_count appears to be unused */
//PRUint16 hist_count; /* Histogram frequency count. */
} GIF_RGB;
/* Colormap information. */
typedef struct _GIF_ColorMap {
int32 num_colors; /* Number of colors in the colormap.
A negative value can be used to denote a
possibly non-unique set. */
GIF_RGB *map; /* Colormap colors. */
PRUint8 *index; /* NULL, if map is in index order. Otherwise
specifies the indices of the map entries. */
void *table; /* Lookup table for this colormap. Private to
the Image Library. */
} GIF_ColorMap;
/* An indexed RGB triplet. */
typedef struct _GIF_IRGB {
PRUint8 index;
PRUint8 red, green, blue;
} GIF_IRGB;
/* A GIF decoder's state */
typedef struct gif_struct {
void* clientptr;
/* Callbacks for this decoder instance*/
int (PR_CALLBACK *GIFCallback_NewPixmap)();
int (PR_CALLBACK *GIFCallback_BeginGIF)(
void* aClientData,
PRUint32 aLogicalScreenWidth,
PRUint32 aLogicalScreenHeight,
PRUint8 aLogicalScreenBackgroundRGBIndex);
int (PR_CALLBACK* GIFCallback_EndGIF)(
void* aClientData,
int aAnimationLoopCount);
int (PR_CALLBACK* GIFCallback_BeginImageFrame)(
void* aClientData,
PRUint32 aFrameNumber, /* Frame number, 1-n */
PRUint32 aFrameXOffset, /* X offset in logical screen */
PRUint32 aFrameYOffset, /* Y offset in logical screen */
PRUint32 aFrameWidth,
PRUint32 aFrameHeight,
GIF_RGB* aTransparencyChromaKey);
int (PR_CALLBACK* GIFCallback_EndImageFrame)(
void* aClientData,
PRUint32 aFrameNumber,
PRUint32 aDelayTimeout);
int (PR_CALLBACK* GIFCallback_SetupColorspaceConverter)();
int (PR_CALLBACK* GIFCallback_ResetPalette)();
int (PR_CALLBACK* GIFCallback_InitTransparentPixel)();
int (PR_CALLBACK* GIFCallback_DestroyTransparentPixel)();
int (PR_CALLBACK* GIFCallback_HaveDecodedRow)(
void* aClientData,
PRUint8* aRowBufPtr, /* Pointer to single scanline temporary buffer */
PRUint8* aRGBrowBufPtr,/* Pointer to temporary storage for dithering/mapping */
int aXOffset, /* With respect to GIF logical screen origin */
int aLength, /* Length of the row? */
int aRow, /* Row number? */
int aDuplicateCount, /* Number of times to duplicate the row? */
PRUint8 aDrawMode, /* il_draw_mode */
int aInterlacePass);
int (PR_CALLBACK *GIFCallback_HaveImageAll)(
void* aClientData);
/* Parsing state machine */
gstate state; /* Curent decoder master state */
PRUint8 *hold; /* Accumulation buffer */
int32 hold_size; /* Capacity, in bytes, of accumulation buffer */
PRUint8 *gather_head; /* Next byte to read in accumulation buffer */
int32 gather_request_size; /* Number of bytes to accumulate */
int32 gathered; /* bytes accumulated so far*/
gstate post_gather_state; /* State after requested bytes accumulated */
int32 requested_buffer_fullness; /* For netscape application extension */
/* LZW decoder state machine */
PRUint8 *stack; /* Base of decoder stack */
PRUint8 *stackp; /* Current stack pointer */
PRUint16 *prefix;
PRUint8 *suffix;
int datasize;
int codesize;
int codemask;
int clear_code; /* Codeword used to trigger dictionary reset */
int avail; /* Index of next available slot in dictionary */
int oldcode;
PRUint8 firstchar;
int count; /* Remaining # bytes in sub-block */
int bits; /* Number of unread bits in "datum" */
int32 datum; /* 32-bit input buffer */
/* Output state machine */
int ipass; /* Interlace pass; Ranges 1-4 if interlaced. */
PRUintn rows_remaining; /* Rows remaining to be output */
PRUintn irow; /* Current output row, starting at zero */
PRUint8 *rgbrow; /* Temporary storage for dithering/mapping */
PRUint8 *rowbuf; /* Single scanline temporary buffer */
PRUint8 *rowend; /* Pointer to end of rowbuf */
PRUint8 *rowp; /* Current output pointer */
/* Parameters for image frame currently being decoded*/
PRUintn x_offset, y_offset; /* With respect to "screen" origin */
PRUintn height, width;
PRUintn last_x_offset, last_y_offset; /* With respect to "screen" origin */
PRUintn last_height, last_width;
int interlaced; /* TRUE, if scanlines arrive interlaced order */
int tpixel; /* Index of transparent pixel */
GIF_IRGB* transparent_pixel;
int is_transparent; /* TRUE, if tpixel is valid */
int control_extension; /* TRUE, if image control extension present */
int is_local_colormap_defined;
gdispose disposal_method; /* Restore to background, leave in place, etc.*/
gdispose last_disposal_method;
GIF_RGB *local_colormap; /* Per-image colormap */
int local_colormap_size; /* Size of local colormap array. */
PRUint32 delay_time; /* Display time, in milliseconds,
for this image in a multi-image GIF */
/* Global (multi-image) state */
int screen_bgcolor; /* Logical screen background color */
int version; /* Either 89 for GIF89 or 87 for GIF87 */
PRUintn screen_width; /* Logical screen width & height */
PRUintn screen_height;
GIF_RGB *global_colormap; /* Default colormap if local not supplied */
int global_colormap_size; /* Size of global colormap array. */
int images_decoded; /* Counts images for multi-part GIFs */
int destroy_pending; /* Stream has ended */
int progressive_display; /* If TRUE, do Haeberli interlace hack */
int loop_count; /* Netscape specific extension block to control
the number of animation loops a GIF renders. */
} gif_struct;
/* Create a new gif_struct */
extern PRBool gif_create(gif_struct **gs);
/* These are the APIs that the client calls to intialize,
push data to, and shut down the GIF decoder. */
PRBool GIFInit(
gif_struct* gs,
void* aClientData,
int (*PR_CALLBACK GIFCallback_NewPixmap)(),
int (*PR_CALLBACK GIFCallback_BeginGIF)(
void* aClientData,
PRUint32 aLogicalScreenWidth,
PRUint32 aLogicalScreenHeight,
PRUint8 aBackgroundRGBIndex),
int (*PR_CALLBACK GIFCallback_EndGIF)(
void* aClientData,
int aAnimationLoopCount),
int (*PR_CALLBACK GIFCallback_BeginImageFrame)(
void* aClientData,
PRUint32 aFrameNumber, /* Frame number, 1-n */
PRUint32 aFrameXOffset, /* X offset in logical screen */
PRUint32 aFrameYOffset, /* Y offset in logical screen */
PRUint32 aFrameWidth,
PRUint32 aFrameHeight,
GIF_RGB* aTransparencyChromaKey),
int (*PR_CALLBACK GIFCallback_EndImageFrame)(
void* aClientData,
PRUint32 aFrameNumber,
PRUint32 aDelayTimeout),
int (*PR_CALLBACK GIFCallback_SetupColorspaceConverter)(),
int (*PR_CALLBACK GIFCallback_ResetPalette)(),
int (*PR_CALLBACK GIFCallback_InitTransparentPixel)(),
int (*PR_CALLBACK GIFCallback_DestroyTransparentPixel)(),
int (*PR_CALLBACK GIFCallback_HaveDecodedRow)(
void* aClientData,
PRUint8* aRowBufPtr, /* Pointer to single scanline temporary buffer */
PRUint8* aRGBrowBufPtr,/* Pointer to temporary storage for dithering/mapping */
int aXOffset, /* With respect to GIF logical screen origin */
int aLength, /* Length of the row? */
int aRow, /* Row number? */
int aDuplicateCount, /* Number of times to duplicate the row? */
PRUint8 aDrawMode, /* il_draw_mode */
int aInterlacePass),
int (*PR_CALLBACK GIFCallback_HaveImageAll)(
void* aClientData)
);
extern void gif_destroy(gif_struct* aGIFStruct);
int gif_write(gif_struct* aGIFStruct, const PRUint8 * buf, PRUint32 numbytes);
PRUint8 gif_write_ready(gif_struct* aGIFStruct);
extern void gif_complete(gif_struct** aGIFStruct);
extern void gif_delay_time_callback(/* void *closure */);
/* Callback functions that the client must implement and pass in
pointers for during the GIFInit call. These will be called back
when the decoder has a decoded rows, frame size information, etc.*/
/* GIFCallback_LogicalScreenSize is called only once to notify the client
of the logical screen size, which will be the size of the total image. */
typedef int (*PR_CALLBACK BEGINGIF_CALLBACK)(
void* aClientData,
PRUint32 aLogicalScreenWidth,
PRUint32 aLogicalScreenHeight,
PRUint8 aLogicalScreenBackgroundRGBIndex);
typedef int (PR_CALLBACK *GIFCallback_EndGIF)(
void* aClientData,
int aAnimationLoopCount);
/* GIFCallback_BeginImageFrame is called at the beginning of each frame of
a GIF.*/
typedef int (PR_CALLBACK *GIFCallback_BeginImageFrame)(
void* aClientData,
PRUint32 aFrameNumber, /* Frame number, 1-n */
PRUint32 aFrameXOffset, /* X offset in logical screen */
PRUint32 aFraqeYOffset, /* Y offset in logical screen */
PRUint32 aFrameWidth,
PRUint32 aFrameHeight);
extern int GIFCallback_EndImageFrame(
void* aClientData,
PRUint32 aFrameNumber,
PRUint32 aDelayTimeout); /* Time in milliseconds this frame should be displayed before the next frame.
This information appears in a sub control block, so we don't
transmit it back to the client until we're done with the frame. */
/*
extern int GIFCallback_SetupColorspaceConverter();
extern int GIFCallback_ResetPalette();
extern int GIFCallback_InitTransparentPixel();
extern int GIFCallback_DestroyTransparentPixel();
*/
extern int GIFCallback_HaveDecodedRow();
extern int GIFCallback_HaveImageAll();
#endif

View File

@@ -0,0 +1,42 @@
#
# The contents of this file are subject to the Mozilla Public
# License Version 1.1 (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/MPL/
#
# 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.org code
#
# The Initial Developer of the Original Code is Netscape
# Communications Corporation. Portions created by Netscape are
# Copyright (C) 2001 Netscape Communications Corporation. All
# Rights Reserved.
#
# Contributor(s):
#
DEPTH = ../../../..
topsrcdir = @top_srcdir@
srcdir = @srcdir@
VPATH = @srcdir@
include $(DEPTH)/config/autoconf.mk
MODULE = imggif
LIBRARY_NAME = imggif
IS_COMPONENT = 1
REQUIRES = xpcom necko layout gfx2 imglib2
CPPSRCS = GIF2.cpp nsGIFDecoder2.cpp nsGIFModule.cpp
EXTRA_DSO_LDOPTS = $(GIF_LIBS) $(ZLIB_LIBS) \
$(MOZ_COMPONENT_LIBS) \
$(NULL)
include $(topsrcdir)/config/rules.mk

View File

@@ -0,0 +1,52 @@
#!nmake
#
# The contents of this file are subject to the Mozilla Public
# License Version 1.1 (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/MPL/
#
# 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.org code
#
# The Initial Developer of the Original Code is Netscape
# Communications Corporation. Portions created by Netscape are
# Copyright (C) 2001 Netscape Communications Corporation. All
# Rights Reserved.
#
# Contributor(s):
# Stuart Parmenter <pavlov@netscape.com>
#
DEPTH=..\..\..\..
include <$(DEPTH)/config/config.mak>
MODULE = imggif
LIBRARY_NAME = imggif
DLL = $(OBJDIR)\$(LIBRARY_NAME).dll
MAKE_OBJ_TYPE = DLL
OBJS = \
.\$(OBJDIR)\nsGIFDecoder2.obj \
.\$(OBJDIR)\GIF2.obj \
.\$(OBJDIR)\nsGIFModule.obj \
$(NULL)
LLIBS=\
$(LIBNSPR) \
$(DIST)\lib\xpcom.lib \
$(DIST)\lib\gkgfxwin.lib \
$(NULL)
include <$(DEPTH)\config\rules.mak>
install:: $(DLL)
$(MAKE_INSTALL) .\$(OBJDIR)\$(LIBRARY_NAME).dll $(DIST)\bin\components
$(MAKE_INSTALL) .\$(OBJDIR)\$(LIBRARY_NAME).lib $(DIST)\lib
clobber::
rm -f $(DIST)\bin\components\$(LIBRARY_NAME).dll
rm -f $(DIST)\lib\$(LIBRARY_NAME).lib

View File

@@ -0,0 +1,506 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
*
* The contents of this file are subject to the Mozilla Public
* License Version 1.1 (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/MPL/
*
* 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.org code.
*
* The Initial Developer of the Original Code is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 2001 Netscape Communications Corporation.
* All Rights Reserved.
*
* Contributor(s):
* Chris Saari <saari@netscape.com>
*/
#include "nsGIFDecoder2.h"
#include "nsIInputStream.h"
#include "nsIComponentManager.h"
#include "nsIImage.h"
#include "nsMemory.h"
#include "imgIContainerObserver.h"
#include "nsRect.h"
//////////////////////////////////////////////////////////////////////
// GIF Decoder Implementation
// This is an adaptor between GIF2 and imgIDecoder
NS_IMPL_ISUPPORTS2(nsGIFDecoder2, imgIDecoder, nsIOutputStream);
nsGIFDecoder2::nsGIFDecoder2()
{
NS_INIT_ISUPPORTS();
mImageFrame = nsnull;
mGIFStruct = nsnull;
mAlphaLine = nsnull;
}
nsGIFDecoder2::~nsGIFDecoder2(void)
{
if (mAlphaLine)
nsMemory::Free(mAlphaLine);
if (mGIFStruct) {
gif_destroy(mGIFStruct);
mGIFStruct = nsnull;
}
}
//******************************************************************************
/** imgIDecoder methods **/
//******************************************************************************
//******************************************************************************
/* void init (in imgIRequest aRequest); */
NS_IMETHODIMP nsGIFDecoder2::Init(imgIRequest *aRequest)
{
mImageRequest = aRequest;
mObserver = do_QueryInterface(aRequest); // we're holding 2 strong refs to the request.
aRequest->GetImage(getter_AddRefs(mImageContainer));
/* do gif init stuff */
/* Always decode to 24 bit pixdepth */
PRBool created = gif_create(&mGIFStruct);
NS_ASSERTION(created, "gif_create failed");
// Call GIF decoder init routine
GIFInit(
mGIFStruct,
this,
NewPixmap,
BeginGIF,
EndGIF,
BeginImageFrame,
EndImageFrame,
SetupColorspaceConverter,
ResetPalette,
InitTransparentPixel,
DestroyTransparentPixel,
HaveDecodedRow,
HaveImageAll);
return NS_OK;
}
//******************************************************************************
/* readonly attribute imgIRequest request; */
NS_IMETHODIMP nsGIFDecoder2::GetRequest(imgIRequest * *aRequest)
{
*aRequest = mImageRequest;
NS_IF_ADDREF(*aRequest);
return NS_OK;
}
//******************************************************************************
/** nsIOutputStream methods **/
//******************************************************************************
//******************************************************************************
/* void close (); */
NS_IMETHODIMP nsGIFDecoder2::Close()
{
if (mGIFStruct) {
gif_destroy(mGIFStruct);
mGIFStruct = nsnull;
}
return NS_OK;
}
//******************************************************************************
/* void flush (); */
NS_IMETHODIMP nsGIFDecoder2::Flush()
{
return NS_ERROR_NOT_IMPLEMENTED;
}
//******************************************************************************
/* unsigned long write (in string buf, in unsigned long count); */
NS_IMETHODIMP nsGIFDecoder2::Write(const char *buf, PRUint32 count, PRUint32 *_retval)
{
return NS_ERROR_NOT_IMPLEMENTED;
}
//******************************************************************************
/* static callback from nsIInputStream::ReadSegments */
static NS_METHOD ReadDataOut(nsIInputStream* in,
void* closure,
const char* fromRawSegment,
PRUint32 toOffset,
PRUint32 count,
PRUint32 *writeCount)
{
nsGIFDecoder2 *decoder = NS_STATIC_CAST(nsGIFDecoder2*, closure);
*writeCount = decoder->ProcessData((unsigned char*)fromRawSegment, count);
return NS_OK;
}
//******************************************************************************
PRUint32 nsGIFDecoder2::ProcessData(unsigned char *data, PRUint32 count)
{
// Push the data to the GIF decoder
// First we ask if the gif decoder is ready for more data, and if so, push it.
// In the new decoder, we should always be able to process more data since
// we don't wait to decode each frame in an animation now.
if(gif_write_ready(mGIFStruct)) {
gif_write(mGIFStruct, data, count);
}
return count; // we always consume all the data
}
//******************************************************************************
/* unsigned long writeFrom (in nsIInputStream inStr, in unsigned long count); */
NS_IMETHODIMP nsGIFDecoder2::WriteFrom(nsIInputStream *inStr, PRUint32 count, PRUint32 *_retval)
{
inStr->ReadSegments(
ReadDataOut, // Callback
this,
count,
_retval);
// if error
//mRequest->Cancel(NS_BINDING_ABORTED); // XXX is this the correct error ?
return NS_OK;
}
//******************************************************************************
/* [noscript] unsigned long writeSegments (in nsReadSegmentFun reader, in voidPtr closure, in unsigned long count); */
NS_IMETHODIMP nsGIFDecoder2::WriteSegments(nsReadSegmentFun reader, void * closure, PRUint32 count, PRUint32 *_retval)
{
return NS_ERROR_NOT_IMPLEMENTED;
}
//******************************************************************************
/* attribute boolean nonBlocking; */
NS_IMETHODIMP nsGIFDecoder2::GetNonBlocking(PRBool *aNonBlocking)
{
return NS_ERROR_NOT_IMPLEMENTED;
}
//******************************************************************************
NS_IMETHODIMP nsGIFDecoder2::SetNonBlocking(PRBool aNonBlocking)
{
return NS_ERROR_NOT_IMPLEMENTED;
}
//******************************************************************************
/* attribute nsIOutputStreamObserver observer; */
NS_IMETHODIMP nsGIFDecoder2::GetObserver(nsIOutputStreamObserver * *aObserver)
{
return NS_ERROR_NOT_IMPLEMENTED;
}
//******************************************************************************
NS_IMETHODIMP nsGIFDecoder2::SetObserver(nsIOutputStreamObserver * aObserver)
{
return NS_ERROR_NOT_IMPLEMENTED;
}
//******************************************************************************
// GIF decoder callback methods. Part of pulic API for GIF2
//******************************************************************************
//******************************************************************************
int BeginGIF(
void* aClientData,
PRUint32 aLogicalScreenWidth,
PRUint32 aLogicalScreenHeight,
PRUint8 aBackgroundRGBIndex)
{
// copy GIF info into imagelib structs
nsGIFDecoder2 *decoder = NS_STATIC_CAST(nsGIFDecoder2*, aClientData);
if (decoder->mObserver)
decoder->mObserver->OnStartDecode(nsnull, nsnull);
decoder->mImageContainer->Init(aLogicalScreenWidth, aLogicalScreenHeight, decoder->mObserver);
if (decoder->mObserver)
decoder->mObserver->OnStartContainer(nsnull, nsnull, decoder->mImageContainer);
return 0;
}
//******************************************************************************
int EndGIF(
void* aClientData,
int aAnimationLoopCount)
{
nsGIFDecoder2 *decoder = NS_STATIC_CAST(nsGIFDecoder2*, aClientData);
if (decoder->mObserver) {
decoder->mObserver->OnStopContainer(nsnull, nsnull, decoder->mImageContainer);
decoder->mObserver->OnStopDecode(nsnull, nsnull, NS_OK, nsnull);
}
decoder->mImageContainer->SetLoopCount(aAnimationLoopCount);
decoder->mImageContainer->DecodingComplete();
return 0;
}
//******************************************************************************
int BeginImageFrame(
void* aClientData,
PRUint32 aFrameNumber, /* Frame number, 1-n */
PRUint32 aFrameXOffset, /* X offset in logical screen */
PRUint32 aFrameYOffset, /* Y offset in logical screen */
PRUint32 aFrameWidth,
PRUint32 aFrameHeight,
GIF_RGB* aTransparencyChromaKey) /* don't have this info yet */
{
nsGIFDecoder2* decoder = NS_STATIC_CAST(nsGIFDecoder2*, aClientData);
decoder->mImageFrame = nsnull; // clear out our current frame reference
decoder->mGIFStruct->x_offset = aFrameXOffset;
decoder->mGIFStruct->y_offset = aFrameYOffset;
decoder->mGIFStruct->width = aFrameWidth;
decoder->mGIFStruct->height = aFrameHeight;
return 0;
}
//******************************************************************************
int EndImageFrame(
void* aClientData,
PRUint32 aFrameNumber,
PRUint32 aDelayTimeout) /* Time this frame should be displayed before the next frame
we can't have this in the image frame init because it doesn't
show up in the GIF frame header, it shows up in a sub control
block.*/
{
nsGIFDecoder2* decoder = NS_STATIC_CAST(nsGIFDecoder2*, aClientData);
// We actually have the timeout information before we get the lzw encoded image
// data, at least according to the spec, but we delay in setting the timeout for
// the image until here to help ensure that we have the whole image frame decoded before
// we go off and try to display another frame.
// XXXXXXXX
// decoder->mImageFrame->SetTimeout(aDelayTimeout);
decoder->mImageContainer->EndFrameDecode(aFrameNumber, aDelayTimeout);
if (decoder->mObserver)
decoder->mObserver->OnStopFrame(nsnull, nsnull, decoder->mImageFrame);
decoder->mImageFrame = nsnull;
return 0;
}
//******************************************************************************
// GIF decoder callback
int HaveImageAll(
void* aClientData)
{
return 0;
}
//******************************************************************************
// GIF decoder callback notification that it has decoded a row
int HaveDecodedRow(
void* aClientData,
PRUint8* aRowBufPtr, // Pointer to single scanline temporary buffer
PRUint8* aRGBrowBufPtr,// Pointer to temporary storage for dithering/mapping
int aXOffset, // With respect to GIF logical screen origin
int aLength, // Length of the row?
int aRowNumber, // Row number?
int aDuplicateCount, // Number of times to duplicate the row?
PRUint8 aDrawMode, // il_draw_mode
int aInterlacePass) // interlace pass (1-4)
{
nsGIFDecoder2* decoder = NS_STATIC_CAST(nsGIFDecoder2*, aClientData);
PRUint32 bpr, abpr;
// We have to delay allocation of the image frame until now because
// we won't have control block info (transparency) until now. The conrol
// block of a GIF stream shows up after the image header since transparency
// is added in GIF89a and control blocks are how the extensions are done.
// How annoying.
if(! decoder->mImageFrame) {
gfx_format format = gfxIFormats::RGB;
if (decoder->mGIFStruct->is_transparent)
format = gfxIFormats::RGB_A1;
#ifdef XP_PC
// XXX this works...
format += 1; // RGB to BGR
#endif
// initalize the frame and append it to the container
decoder->mImageFrame = do_CreateInstance("@mozilla.org/gfx/image/frame;2");
decoder->mImageFrame->Init(
decoder->mGIFStruct->x_offset, decoder->mGIFStruct->y_offset,
decoder->mGIFStruct->width, decoder->mGIFStruct->height, format);
decoder->mImageContainer->AppendFrame(decoder->mImageFrame);
if (decoder->mObserver)
decoder->mObserver->OnStartFrame(nsnull, nsnull, decoder->mImageFrame);
decoder->mImageFrame->GetImageBytesPerRow(&bpr);
decoder->mImageFrame->GetAlphaBytesPerRow(&abpr);
if (format == gfxIFormats::RGB_A1 || format == gfxIFormats::BGR_A1) {
if (decoder->mAlphaLine)
nsMemory::Free(decoder->mAlphaLine);
decoder->mAlphaLine = (PRUint8 *)nsMemory::Alloc(abpr);
}
} else {
decoder->mImageFrame->GetImageBytesPerRow(&bpr);
decoder->mImageFrame->GetAlphaBytesPerRow(&abpr);
}
if (aRowBufPtr) {
nscoord width;
decoder->mImageFrame->GetWidth(&width);
PRUint32 iwidth = width;
gfx_format format;
decoder->mImageFrame->GetFormat(&format);
// XXX map the data into colors
int cmapsize;
GIF_RGB* cmap;
if(decoder->mGIFStruct->local_colormap) {
cmapsize = decoder->mGIFStruct->local_colormap_size;
cmap = decoder->mGIFStruct->local_colormap;
} else {
cmapsize = decoder->mGIFStruct->global_colormap_size;
cmap = decoder->mGIFStruct->global_colormap;
}
PRUint8* rgbRowIndex = aRGBrowBufPtr;
PRUint8* rowBufIndex = aRowBufPtr;
switch (format) {
case gfxIFormats::RGB:
{
while(rowBufIndex != decoder->mGIFStruct->rowend) {
#ifdef XP_MAC
*rgbRowIndex++ = 0; // Mac is always 32bits per pixel, this is pad
#endif
*rgbRowIndex++ = cmap[PRUint8(*rowBufIndex)].red;
*rgbRowIndex++ = cmap[PRUint8(*rowBufIndex)].green;
*rgbRowIndex++ = cmap[PRUint8(*rowBufIndex)].blue;
++rowBufIndex;
}
decoder->mImageFrame->SetImageData((PRUint8*)aRGBrowBufPtr, bpr, aRowNumber*bpr);
}
break;
case gfxIFormats::BGR:
{
while(rowBufIndex != decoder->mGIFStruct->rowend) {
*rgbRowIndex++ = cmap[PRUint8(*rowBufIndex)].blue;
*rgbRowIndex++ = cmap[PRUint8(*rowBufIndex)].green;
*rgbRowIndex++ = cmap[PRUint8(*rowBufIndex)].red;
++rowBufIndex;
}
decoder->mImageFrame->SetImageData((PRUint8*)aRGBrowBufPtr, bpr, aRowNumber*bpr);
}
break;
case gfxIFormats::RGB_A1:
case gfxIFormats::BGR_A1:
{
memset(aRGBrowBufPtr, 0, bpr);
memset(decoder->mAlphaLine, 0, abpr);
PRUint32 iwidth = (PRUint32)width;
for (PRUint32 x=0; x<iwidth; x++) {
if (*rowBufIndex != decoder->mGIFStruct->tpixel) {
#ifdef XP_PC
*rgbRowIndex++ = cmap[PRUint8(*rowBufIndex)].blue;
*rgbRowIndex++ = cmap[PRUint8(*rowBufIndex)].green;
*rgbRowIndex++ = cmap[PRUint8(*rowBufIndex)].red;
#else
#ifdef XP_MAC
*rgbRowIndex++ = 0; // Mac is always 32bits per pixel, this is pad
#endif
*rgbRowIndex++ = cmap[PRUint8(*rowBufIndex)].red;
*rgbRowIndex++ = cmap[PRUint8(*rowBufIndex)].green;
*rgbRowIndex++ = cmap[PRUint8(*rowBufIndex)].blue;
#endif
decoder->mAlphaLine[x>>3] |= 1<<(7-x&0x7);
} else {
#ifdef XP_MAC
rgbRowIndex+=4;
#else
rgbRowIndex+=3;
#endif
}
++rowBufIndex;
}
decoder->mImageFrame->SetImageData((PRUint8*)aRGBrowBufPtr, bpr, aRowNumber*bpr);
decoder->mImageFrame->SetAlphaData(decoder->mAlphaLine, abpr, aRowNumber*abpr);
}
break;
default:
break;
}
nsRect r(0, aRowNumber, width, 1);
decoder->mObserver->OnDataAvailable(nsnull, nsnull, decoder->mImageFrame, &r);
}
return 0;
}
//******************************************************************************
int ResetPalette()
{
return 0;
}
//******************************************************************************
int SetupColorspaceConverter()
{
return 0;
}
//******************************************************************************
int EndImageFrame()
{
return 0;
}
//******************************************************************************
int NewPixmap()
{
return 0;
}
//******************************************************************************
int InitTransparentPixel()
{
return 0;
}
//******************************************************************************
int DestroyTransparentPixel()
{
return 0;
}

View File

@@ -0,0 +1,114 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
*
* The contents of this file are subject to the Mozilla Public
* License Version 1.1 (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/MPL/
*
* 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.org code.
*
* The Initial Developer of the Original Code is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 2001 Netscape Communications Corporation.
* All Rights Reserved.
*
* Contributor(s):
* Chris Saari <saari@netscape.com>
*/
#ifndef _nsGIFDecoder2_h
#define _nsGIFDecoder2_h
#include "nsCOMPtr.h"
#include "imgIDecoder.h"
#include "imgIContainer.h"
#include "imgIDecoderObserver.h"
#include "gfxIImageFrame.h"
#include "imgIRequest.h"
#include "GIF2.h"
#define NS_GIFDECODER2_CID \
{ /* 797bec5a-1dd2-11b2-a7f8-ca397e0179c4 */ \
0x797bec5a, \
0x1dd2, \
0x11b2, \
{0xa7, 0xf8, 0xca, 0x39, 0x7e, 0x01, 0x79, 0xc4} \
}
//////////////////////////////////////////////////////////////////////
// nsGIFDecoder2 Definition
class nsGIFDecoder2 : public imgIDecoder
{
public:
NS_DECL_ISUPPORTS
NS_DECL_IMGIDECODER
NS_DECL_NSIOUTPUTSTREAM
nsGIFDecoder2();
virtual ~nsGIFDecoder2();
static NS_METHOD Create(nsISupports *aOuter, REFNSIID aIID, void **aResult);
NS_METHOD ProcessData(unsigned char *data, PRUint32 count);
nsCOMPtr<imgIContainer> mImageContainer;
nsCOMPtr<gfxIImageFrame> mImageFrame;
nsCOMPtr<imgIRequest> mImageRequest;
nsCOMPtr<imgIDecoderObserver> mObserver; // this is just qi'd from mRequest for speed
gif_struct *mGIFStruct;
PRUint8 *mAlphaLine;
};
// static callbacks for the GIF decoder
static int PR_CALLBACK BeginGIF(
void* aClientData,
PRUint32 aLogicalScreenWidth,
PRUint32 aLogicalScreenHeight,
PRUint8 aBackgroundRGBIndex);
static int PR_CALLBACK HaveDecodedRow(
void* aClientData,
PRUint8* aRowBufPtr, // Pointer to single scanline temporary buffer
PRUint8* aRGBrowBufPtr,// Pointer to temporary storage for dithering/mapping
int aXOffset, // With respect to GIF logical screen origin
int aLength, // Length of the row?
int aRow, // Row number?
int aDuplicateCount, // Number of times to duplicate the row?
PRUint8 aDrawMode, // il_draw_mode
int aInterlacePass);
static int PR_CALLBACK NewPixmap();
static int PR_CALLBACK EndGIF(
void* aClientData,
int aAnimationLoopCount);
static int PR_CALLBACK BeginImageFrame(
void* aClientData,
PRUint32 aFrameNumber, /* Frame number, 1-n */
PRUint32 aFrameXOffset, /* X offset in logical screen */
PRUint32 aFrameYOffset, /* Y offset in logical screen */
PRUint32 aFrameWidth,
PRUint32 aFrameHeight,
GIF_RGB* aTransparencyChromaKey);
static int PR_CALLBACK EndImageFrame(
void* aClientData,
PRUint32 aFrameNumber,
PRUint32 aDelayTimeout);
static int PR_CALLBACK SetupColorspaceConverter();
static int PR_CALLBACK ResetPalette();
static int PR_CALLBACK InitTransparentPixel();
static int PR_CALLBACK DestroyTransparentPixel();
static int PR_CALLBACK HaveImageAll(
void* aClientData);
#endif

View File

@@ -0,0 +1,41 @@
/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
*
* The contents of this file are subject to the Netscape Public
* License Version 1.1 (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.org 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.
*
* Contributor(s):
* Chris Saari <saari@netscape.com>
*/
#include "nsGIFDecoder2.h"
#include "nsIComponentManager.h"
#include "nsIGenericFactory.h"
#include "nsISupports.h"
#include "nsCOMPtr.h"
NS_GENERIC_FACTORY_CONSTRUCTOR(nsGIFDecoder2)
static nsModuleComponentInfo components[] =
{
{ "GIF Decoder",
NS_GIFDECODER2_CID,
"@mozilla.org/image/decoder;2?type=image/gif",
nsGIFDecoder2Constructor, },
};
NS_IMPL_NSGETMODULE("nsGIFModule2", components)

View File

@@ -0,0 +1,18 @@
?AddRef@nsGIFDecoder2@@UAGKXZ ; 2550
?Release@nsGIFDecoder2@@UAGKXZ ; 2550
?gif_write_ready@@YAEPAUgif_struct@@@Z ; 1624
?ProcessData@nsGIFDecoder2@@QAGIPAEI@Z ; 1624
?gif_write@@YAHPAUgif_struct@@PBEI@Z ; 1624
?WriteFrom@nsGIFDecoder2@@UAGIPAVnsIInputStream@@IPAI@Z ; 1309
?Close@nsGIFDecoder2@@UAGIXZ ; 1275
??_GnsGIFDecoder2@@UAEPAXI@Z ; 1275
??0nsGIFDecoder2@@QAE@XZ ; 1275
??1nsGIFDecoder2@@UAE@XZ ; 1275
?QueryInterface@nsGIFDecoder2@@UAGIABUnsID@@PAPAX@Z ; 1275
?GIFInit@@YAHPAUgif_struct@@PAXP6AHXZP6AH1IIE@ZP6AH1H@ZP6AH1IIIIIPAU_GIF_RGB@@@ZP6AH1II@Z2222P6AH1PAE8HHHHEH@ZP6AH1@Z@Z ; 1275
?Init@nsGIFDecoder2@@UAGIPAVimgIRequest@@@Z ; 1275
?Flush@nsGIFDecoder2@@UAGIXZ ; 1275
?gif_destroy@@YAXPAUgif_struct@@@Z ; 1275
?gif_create@@YAHPAPAUgif_struct@@@Z ; 1275
?il_BACat@@YAPADPAPADIPBDI@Z ; 698
_NSGetModule ; 1

View File

@@ -0,0 +1,378 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 4 -*-
*
* The contents of this file are subject to the Mozilla Public
* License Version 1.1 (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/MPL/
*
* 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.org code.
*
* The Initial Developer of the Original Code is Brian Ryner.
* Portions created by Brian Ryner are Copyright (C) 2000 Brian Ryner.
* All Rights Reserved.
*
* Contributor(s):
* Scott MacGregor <mscott@netscape.com>
*/
#include "nsIconChannel.h"
#include "nsIServiceManager.h"
#include "nsIInterfaceRequestor.h"
#include "nsXPIDLString.h"
#include "nsMimeTypes.h"
#include "nsMemory.h"
#include "nsIStringStream.h"
#include "nsIURL.h"
#include "nsNetUtil.h"
#include "nsIMimeService.h"
#include "nsCExternalHandlerService.h"
#include "plstr.h"
#include <Files.h>
#include <QuickDraw.h>
// nsIconChannel methods
nsIconChannel::nsIconChannel()
{
NS_INIT_REFCNT();
mStatus = NS_OK;
}
nsIconChannel::~nsIconChannel()
{}
NS_IMPL_THREADSAFE_ISUPPORTS2(nsIconChannel,
nsIChannel,
nsIRequest)
nsresult nsIconChannel::Init(nsIURI* uri)
{
nsresult rv;
NS_ASSERTION(uri, "no uri");
mUrl = uri;
return NS_OK;
}
////////////////////////////////////////////////////////////////////////////////
// nsIRequest methods:
NS_IMETHODIMP nsIconChannel::GetName(PRUnichar* *result)
{
return NS_ERROR_NOT_IMPLEMENTED;
}
NS_IMETHODIMP nsIconChannel::IsPending(PRBool *result)
{
NS_NOTREACHED("nsIconChannel::IsPending");
return NS_ERROR_NOT_IMPLEMENTED;
}
NS_IMETHODIMP nsIconChannel::GetStatus(nsresult *status)
{
*status = mStatus;
return NS_OK;
}
NS_IMETHODIMP nsIconChannel::Cancel(nsresult status)
{
NS_ASSERTION(NS_FAILED(status), "shouldn't cancel with a success code");
nsresult rv = NS_ERROR_FAILURE;
mStatus = status;
return rv;
}
NS_IMETHODIMP nsIconChannel::Suspend(void)
{
NS_NOTREACHED("nsIconChannel::Suspend");
return NS_ERROR_NOT_IMPLEMENTED;
}
NS_IMETHODIMP nsIconChannel::Resume(void)
{
NS_NOTREACHED("nsIconChannel::Resume");
return NS_ERROR_NOT_IMPLEMENTED;
}
////////////////////////////////////////////////////////////////////////////////
// nsIChannel methods:
NS_IMETHODIMP nsIconChannel::GetOriginalURI(nsIURI* *aURI)
{
*aURI = mOriginalURI ? mOriginalURI : mUrl;
NS_ADDREF(*aURI);
return NS_OK;
}
NS_IMETHODIMP nsIconChannel::SetOriginalURI(nsIURI* aURI)
{
mOriginalURI = aURI;
return NS_OK;
}
NS_IMETHODIMP nsIconChannel::GetURI(nsIURI* *aURI)
{
*aURI = mUrl;
NS_IF_ADDREF(*aURI);
return NS_OK;
}
NS_IMETHODIMP nsIconChannel::SetURI(nsIURI* aURI)
{
mUrl = aURI;
return NS_OK;
}
NS_IMETHODIMP
nsIconChannel::Open(nsIInputStream **_retval)
{
return NS_ERROR_FAILURE;
}
NS_IMETHODIMP nsIconChannel::AsyncOpen(nsIStreamListener *aListener, nsISupports *ctxt)
{
// get the file name from the url
nsXPIDLCString fileName; // will contain a dummy file we'll use to figure out the type of icon desired.
nsXPIDLCString filePath; // will contain an optional parameter for small vs. large icon. default is small
mUrl->GetHost(getter_Copies(fileName));
nsCOMPtr<nsIURL> url (do_QueryInterface(mUrl));
if (url)
url->GetFileBaseName(getter_Copies(filePath));
nsresult rv = NS_OK;
nsCOMPtr<nsIMIMEService> mimeService (do_GetService(NS_MIMESERVICE_CONTRACTID, &rv));
NS_ENSURE_SUCCESS(rv, rv);
// extract the extension out of the dummy file so we can look it up in the mime service.
char * chFileName = fileName.get(); // get the underlying buffer
char * fileExtension = PL_strrchr(chFileName, '.');
if (!fileExtension) return NS_ERROR_FAILURE; // no file extension to work from.
// look the file extension up in the registry.
nsCOMPtr<nsIMIMEInfo> mimeInfo;
mimeService->GetFromExtension(fileExtension, getter_AddRefs(mimeInfo));
NS_ENSURE_TRUE(mimeInfo, NS_ERROR_FAILURE);
// get the mac creator and file type for this mime object
PRUint32 macType;
PRUint32 macCreator;
mimeInfo->GetMacType(&macType);
mimeInfo->GetMacCreator(&macCreator);
// get a refernce to the desktop database
DTPBRec pb;
OSErr err = noErr;
memset(&pb, 0, sizeof(DTPBRec));
pb.ioCompletion = nil;
pb.ioVRefNum = 0; // default desktop volume
pb.ioNamePtr = nil;
err = PBDTGetPath(&pb);
if (err != noErr) return NS_ERROR_FAILURE;
pb.ioFileCreator = macCreator;
pb.ioFileType = macType;
pb.ioCompletion = nil;
pb.ioTagInfo = 0;
PRUint32 numPixelsInRow = 0;
if (filePath && !nsCRT::strcmp(filePath, "large"))
{
pb.ioDTReqCount = kLarge8BitIconSize;
pb.ioIconType = kLarge8BitIcon;
numPixelsInRow = 32;
}
else
{
pb.ioDTReqCount = kSmall8BitIconSize;
pb.ioIconType = kSmall8BitIcon;
numPixelsInRow = 16;
}
// allocate a buffer large enough to handle the icon
PRUint8 * bitmapData = (PRUint8 *) nsMemory::Alloc (pb.ioDTReqCount);
pb.ioDTBuffer = (Ptr) bitmapData;
err = PBDTGetIcon(&pb, false);
if (err != noErr) return NS_ERROR_FAILURE; // unable to fetch the icon....
nsCString iconBuffer;
iconBuffer.Assign((char) numPixelsInRow);
iconBuffer.Append((char) numPixelsInRow);
CTabHandle cTabHandle = GetCTable(72);
if (!cTabHandle) return NS_ERROR_FAILURE;
HLock((Handle) cTabHandle);
CTabPtr colTable = *cTabHandle;
RGBColor rgbCol;
PRUint8 redValue, greenValue, blueValue;
for (PRUint32 index = 0; index < pb.ioDTReqCount; index ++)
{
// each byte in bitmapData needs to be converted from an 8 bit system color into
// 24 bit RGB data which our special icon image decoder can understand.
ColorSpec colSpec = colTable->ctTable[ bitmapData[index]];
rgbCol = colSpec.rgb;
redValue = rgbCol.red & 0xff;
greenValue = rgbCol.green & 0xff;
blueValue = rgbCol.blue & 0xff;
// for some reason the image code on the mac expects each RGB pixel value to be padded with a preceding byte.
// so add the padding here....
iconBuffer.Append((char) 0);
iconBuffer.Append((char) redValue);
iconBuffer.Append((char) greenValue);
iconBuffer.Append((char) blueValue);
}
HUnlock((Handle) cTabHandle);
DisposeCTable(cTabHandle);
nsMemory::Free(bitmapData);
// now that the color bitmask is taken care of, we need to do the same thing again for the transparency
// bit mask....
if (filePath && !nsCRT::strcmp(filePath, "large"))
{
pb.ioDTReqCount = kLargeIconSize;
pb.ioIconType = kLargeIcon;
}
else
{
pb.ioDTReqCount = kSmallIconSize;
pb.ioIconType = kSmallIcon;
}
// allocate a buffer large enough to handle the icon
bitmapData = (PRUint8 *) nsMemory::Alloc (pb.ioDTReqCount);
pb.ioDTBuffer = (Ptr) bitmapData;
err = PBDTGetIcon(&pb, false);
PRUint32 index = pb.ioDTReqCount/2;
while (index < pb.ioDTReqCount)
{
iconBuffer.Append((char) bitmapData[index]);
iconBuffer.Append((char) bitmapData[index + 1]);
if (numPixelsInRow == 32)
{
iconBuffer.Append((char) bitmapData[index + 2]);
iconBuffer.Append((char) bitmapData[index + 3]);
index += 4;
}
else
{
iconBuffer.Append((char) 255); // 2 bytes of padding
iconBuffer.Append((char) 255);
index += 2;
}
}
nsMemory::Free(bitmapData);
// turn our nsString into a stream looking object...
aListener->OnStartRequest(this, ctxt);
// turn our string into a stream...
nsCOMPtr<nsISupports> streamSupports;
NS_NewByteInputStream(getter_AddRefs(streamSupports), iconBuffer.get(), iconBuffer.Length());
nsCOMPtr<nsIInputStream> inputStr (do_QueryInterface(streamSupports));
aListener->OnDataAvailable(this, ctxt, inputStr, 0, iconBuffer.Length());
aListener->OnStopRequest(this, ctxt, NS_OK, nsnull);
return NS_OK;
}
NS_IMETHODIMP nsIconChannel::GetLoadAttributes(PRUint32 *aLoadAttributes)
{
*aLoadAttributes = mLoadAttributes;
return NS_OK;
}
NS_IMETHODIMP nsIconChannel::SetLoadAttributes(PRUint32 aLoadAttributes)
{
mLoadAttributes = aLoadAttributes;
return NS_OK;
}
NS_IMETHODIMP nsIconChannel::GetContentType(char* *aContentType)
{
if (!aContentType) return NS_ERROR_NULL_POINTER;
*aContentType = nsCRT::strdup("image/icon");
if (!*aContentType) return NS_ERROR_OUT_OF_MEMORY;
return NS_OK;
}
NS_IMETHODIMP
nsIconChannel::SetContentType(const char *aContentType)
{
//It doesn't make sense to set the content-type on this type
// of channel...
return NS_ERROR_FAILURE;
}
NS_IMETHODIMP nsIconChannel::GetContentLength(PRInt32 *aContentLength)
{
*aContentLength = mContentLength;
return NS_OK;
}
NS_IMETHODIMP nsIconChannel::SetContentLength(PRInt32 aContentLength)
{
NS_NOTREACHED("nsIconChannel::SetContentLength");
return NS_ERROR_NOT_IMPLEMENTED;
}
NS_IMETHODIMP nsIconChannel::GetLoadGroup(nsILoadGroup* *aLoadGroup)
{
*aLoadGroup = mLoadGroup;
NS_IF_ADDREF(*aLoadGroup);
return NS_OK;
}
NS_IMETHODIMP nsIconChannel::SetLoadGroup(nsILoadGroup* aLoadGroup)
{
mLoadGroup = aLoadGroup;
return NS_OK;
}
NS_IMETHODIMP nsIconChannel::GetOwner(nsISupports* *aOwner)
{
*aOwner = mOwner.get();
NS_IF_ADDREF(*aOwner);
return NS_OK;
}
NS_IMETHODIMP nsIconChannel::SetOwner(nsISupports* aOwner)
{
mOwner = aOwner;
return NS_OK;
}
NS_IMETHODIMP nsIconChannel::GetNotificationCallbacks(nsIInterfaceRequestor* *aNotificationCallbacks)
{
*aNotificationCallbacks = mCallbacks.get();
NS_IF_ADDREF(*aNotificationCallbacks);
return NS_OK;
}
NS_IMETHODIMP nsIconChannel::SetNotificationCallbacks(nsIInterfaceRequestor* aNotificationCallbacks)
{
mCallbacks = aNotificationCallbacks;
return NS_OK;
}
NS_IMETHODIMP nsIconChannel::GetSecurityInfo(nsISupports * *aSecurityInfo)
{
*aSecurityInfo = nsnull;
return NS_OK;
}

View File

@@ -0,0 +1,56 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 4 -*-
*
* The contents of this file are subject to the Mozilla Public
* License Version 1.1 (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/MPL/
*
* 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.org code.
*
* The Initial Developer of the Original Code is Brian Ryner.
* Portions created by Brian Ryner are Copyright (C) 2000 Brian Ryner.
* All Rights Reserved.
*
* Contributor(s):
* Scott MacGregor <mscott@netscape.com>
*/
#ifndef nsIconChannel_h___
#define nsIconChannel_h___
#include "nsCOMPtr.h"
#include "nsXPIDLString.h"
#include "nsIChannel.h"
#include "nsILoadGroup.h"
#include "nsIInterfaceRequestor.h"
#include "nsIURI.h"
class nsIconChannel : public nsIChannel
{
public:
NS_DECL_ISUPPORTS
NS_DECL_NSIREQUEST
NS_DECL_NSICHANNEL
nsIconChannel();
virtual ~nsIconChannel();
nsresult Init(nsIURI* uri);
protected:
nsCOMPtr<nsIURI> mUrl;
nsCOMPtr<nsIURI> mOriginalURI;
PRUint32 mLoadAttributes;
PRInt32 mContentLength;
nsCOMPtr<nsILoadGroup> mLoadGroup;
nsCOMPtr<nsIInterfaceRequestor> mCallbacks;
nsCOMPtr<nsISupports> mOwner;
nsresult mStatus;
};
#endif /* nsIconChannel_h___ */

View File

@@ -0,0 +1,62 @@
#!nmake
#
# The contents of this file are subject to the Mozilla Public
# License Version 1.1 (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/MPL/
#
# 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.org code
#
# The Initial Developer of the Original Code is Netscape
# Communications Corporation. Portions created by Netscape are
# Copyright (C) 2001 Netscape Communications Corporation. All
# Rights Reserved.
#
# Contributor(s):
# Scott MacGregor <mscott@netscape.com>
#
DEPTH=..\..\..\..
include <$(DEPTH)/config/config.mak>
DIR=win
MODULE = imgicon
LIBRARY_NAME = imgicon
DLL = $(OBJDIR)\$(LIBRARY_NAME).dll
MAKE_OBJ_TYPE = DLL
OBJS = \
.\$(OBJDIR)\nsIconDecoder.obj \
.\$(OBJDIR)\nsIconModule.obj \
.\$(OBJDIR)\nsIconProtocolHandler.obj \
$(NULL)
LLIBS=\
$(LIBNSPR) \
$(DIST)\lib\xpcom.lib \
$(DIST)\lib\gkgfxwin.lib \
$(DIST)\lib\imgiconwin_s.lib \
$(NULL)
WIN_LIBS= shell32.lib
INCS = $(INCS) \
-I$(DEPTH)\dist\include \
-I$(DEPTH)\modules\libpr0n\decoders\icon\win \
$(NULL)
include <$(DEPTH)\config\rules.mak>
install:: $(DLL)
$(MAKE_INSTALL) .\$(OBJDIR)\$(LIBRARY_NAME).dll $(DIST)\bin\components
$(MAKE_INSTALL) .\$(OBJDIR)\$(LIBRARY_NAME).lib $(DIST)\lib
clobber::
rm -f $(DIST)\bin\components\$(LIBRARY_NAME).dll
rm -f $(DIST)\lib\$(LIBRARY_NAME).lib

View File

@@ -0,0 +1,195 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
*
* The contents of this file are subject to the Mozilla Public
* License Version 1.1 (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/MPL/
*
* 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.org code.
*
* The Initial Developer of the Original Code is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 2001 Netscape Communications Corporation.
* All Rights Reserved.
*
* Contributor(s):
* Scott MacGregor <mscott@netscape.com>
*
*/
#include "nsIconDecoder.h"
#include "nsIInputStream.h"
#include "imgIContainer.h"
#include "imgIContainerObserver.h"
#include "nspr.h"
#include "nsIComponentManager.h"
#include "nsRect.h"
NS_IMPL_THREADSAFE_ADDREF(nsIconDecoder);
NS_IMPL_THREADSAFE_RELEASE(nsIconDecoder);
NS_INTERFACE_MAP_BEGIN(nsIconDecoder)
NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIOutputStream)
NS_INTERFACE_MAP_ENTRY(nsIOutputStream)
NS_INTERFACE_MAP_ENTRY(imgIDecoder)
NS_INTERFACE_MAP_END_THREADSAFE
nsIconDecoder::nsIconDecoder()
{
NS_INIT_ISUPPORTS();
}
nsIconDecoder::~nsIconDecoder()
{ }
/** imgIDecoder methods **/
NS_IMETHODIMP nsIconDecoder::Init(imgIRequest *aRequest)
{
mRequest = aRequest;
mObserver = do_QueryInterface(aRequest); // we're holding 2 strong refs to the request.
aRequest->GetImage(getter_AddRefs(mImage));
mFrame = do_CreateInstance("@mozilla.org/gfx/image/frame;2");
if (!mFrame) return NS_ERROR_FAILURE;
return NS_OK;
}
NS_IMETHODIMP nsIconDecoder::GetRequest(imgIRequest * *aRequest)
{
*aRequest = mRequest;
NS_ADDREF(*aRequest);
return NS_OK;
}
/** nsIOutputStream methods **/
NS_IMETHODIMP nsIconDecoder::Close()
{
if (mObserver)
{
mObserver->OnStopFrame(nsnull, nsnull, mFrame);
mObserver->OnStopContainer(nsnull, nsnull, mImage);
mObserver->OnStopDecode(nsnull, nsnull, NS_OK, nsnull);
}
return NS_OK;
}
NS_IMETHODIMP nsIconDecoder::Flush()
{
return NS_ERROR_NOT_IMPLEMENTED;
}
NS_IMETHODIMP nsIconDecoder::Write(const char *buf, PRUint32 count, PRUint32 *_retval)
{
return NS_ERROR_NOT_IMPLEMENTED;
}
NS_IMETHODIMP nsIconDecoder::WriteFrom(nsIInputStream *inStr, PRUint32 count, PRUint32 *_retval)
{
nsresult rv;
char *buf = (char *)PR_Malloc(count);
if (!buf) return NS_ERROR_OUT_OF_MEMORY; /* we couldn't allocate the object */
// read the data from the input stram...
PRUint32 readLen;
rv = inStr->Read(buf, count, &readLen);
char *data = buf;
if (NS_FAILED(rv)) return rv;
// since WriteFrom is only called once, go ahead and fire the on start notifications..
mObserver->OnStartDecode(nsnull, nsnull);
PRUint32 i = 0;
// Read size
PRInt32 w, h;
w = data[0];
h = data[1];
data += 2;
readLen -= i + 2;
mImage->Init(w, h, mObserver);
if (mObserver)
mObserver->OnStartContainer(nsnull, nsnull, mImage);
mFrame->Init(0, 0, w, h, gfxIFormats::RGB_A1);
mImage->AppendFrame(mFrame);
if (mObserver)
mObserver->OnStartFrame(nsnull, nsnull, mFrame);
PRUint32 bpr, abpr;
nscoord width, height;
mFrame->GetImageBytesPerRow(&bpr);
mFrame->GetAlphaBytesPerRow(&abpr);
mFrame->GetWidth(&width);
mFrame->GetHeight(&height);
i = 0;
PRInt32 rownum = 0; // XXX this better not have a decimal
PRInt32 wroteLen = 0;
do
{
PRUint8 *line = (PRUint8*)data + i*bpr;
mFrame->SetImageData(line, bpr, (rownum++)*bpr);
nsRect r(0, rownum, width, 1);
mObserver->OnDataAvailable(nsnull, nsnull, mFrame, &r);
wroteLen += bpr ;
i++;
} while(rownum < height);
// now we want to send in the alpha data...
for (rownum = 0; rownum < height; rownum ++)
{
PRUint8 * line = (PRUint8*) data + abpr * rownum + height*bpr;
mFrame->SetAlphaData(line, abpr, (rownum)*abpr);
}
PR_FREEIF(buf);
return NS_OK;
}
NS_IMETHODIMP nsIconDecoder::WriteSegments(nsReadSegmentFun reader, void * closure, PRUint32 count, PRUint32 *_retval)
{
return NS_ERROR_NOT_IMPLEMENTED;
}
NS_IMETHODIMP nsIconDecoder::GetNonBlocking(PRBool *aNonBlocking)
{
return NS_ERROR_NOT_IMPLEMENTED;
}
NS_IMETHODIMP nsIconDecoder::SetNonBlocking(PRBool aNonBlocking)
{
return NS_ERROR_NOT_IMPLEMENTED;
}
NS_IMETHODIMP nsIconDecoder::GetObserver(nsIOutputStreamObserver * *aObserver)
{
return NS_ERROR_NOT_IMPLEMENTED;
}
NS_IMETHODIMP nsIconDecoder::SetObserver(nsIOutputStreamObserver * aObserver)
{
return NS_ERROR_NOT_IMPLEMENTED;
}

View File

@@ -0,0 +1,79 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
*
* The contents of this file are subject to the Mozilla Public
* License Version 1.1 (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/MPL/
*
* 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.org code.
*
* The Initial Developer of the Original Code is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 2001 Netscape Communications Corporation.
* All Rights Reserved.
*
* Contributor(s):
* Scott MacGregor <mscott@netscape.com>
*/
#ifndef nsIconDecoder_h__
#define nsIconDecoder_h__
#include "imgIDecoder.h"
#include "nsCOMPtr.h"
#include "imgIContainer.h"
#include "imgIDecoderObserver.h"
#include "gfxIImageFrame.h"
#include "imgIRequest.h"
#define NS_ICONDECODER_CID \
{ /* FFC08380-256C-11d5-9905-001083010E9B */ \
0xffc08380, \
0x256c, \
0x11d5, \
{ 0x99, 0x5, 0x0, 0x10, 0x83, 0x1, 0xe, 0x9b } \
}
//////////////////////////////////////////////////////////////////////////////////////////////
// The icon decoder is a decoder specifically tailored for loading icons
// from the OS. We've defined our own little format to represent these icons
// and this decoder takes that format and converts it into 24-bit RGB with alpha channel
// support. It was modeled a bit off the PPM decoder.
//
// Assumptions about the decoder:
// (1) We receive ALL of the data from the icon channel in one OnDataAvailable call. We don't
// support multiple ODA calls yet.
// (2) the format of the incoming data is as follows:
// The first two bytes contain the width and the height of the icon.
// Followed by 3 bytes per pixel for the color bitmap row after row. (for heigh * width * 3 bytes)
// Followed by bit mask data (used for transparency on the alpha channel).
//
//
//////////////////////////////////////////////////////////////////////////////////////////////
class nsIconDecoder : public imgIDecoder
{
public:
NS_DECL_ISUPPORTS
NS_DECL_IMGIDECODER
NS_DECL_NSIOUTPUTSTREAM
nsIconDecoder();
virtual ~nsIconDecoder();
private:
nsCOMPtr<imgIContainer> mImage;
nsCOMPtr<gfxIImageFrame> mFrame;
nsCOMPtr<imgIRequest> mRequest;
nsCOMPtr<imgIDecoderObserver> mObserver; // this is just qi'd from mRequest for speed
};
#endif // nsIconDecoder_h__

View File

@@ -0,0 +1,54 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
*
* The contents of this file are subject to the Mozilla Public
* License Version 1.1 (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/MPL/
*
* 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.org code.
*
* The Initial Developer of the Original Code is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 2001 Netscape Communications Corporation. All
* Rights Reserved.
*
* Contributor(s):
* Scott MacGregor <mscott@netscape.com>
*/
#include "nsIGenericFactory.h"
#include "nsIModule.h"
#include "nsIconDecoder.h"
#include "nsIconProtocolHandler.h"
// objects that just require generic constructors
/******************************************************************************
* Protocol CIDs
*/
#define NS_ICONPROTOCOL_CID { 0xd0f9db12, 0x249c, 0x11d5, { 0x99, 0x5, 0x0, 0x10, 0x83, 0x1, 0xe, 0x9b } }
NS_GENERIC_FACTORY_CONSTRUCTOR(nsIconDecoder)
NS_GENERIC_FACTORY_CONSTRUCTOR(nsIconProtocolHandler)
static nsModuleComponentInfo components[] =
{
{ "icon decoder",
NS_ICONDECODER_CID,
"@mozilla.org/image/decoder;2?type=image/icon",
nsIconDecoderConstructor, },
{ "Icon Protocol Handler",
NS_ICONPROTOCOL_CID,
NS_NETWORK_PROTOCOL_CONTRACTID_PREFIX "icon",
nsIconProtocolHandlerConstructor
}
};
NS_IMPL_NSGETMODULE("nsIconDecoderModule", components)

View File

@@ -0,0 +1,90 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 4 -*-
*
* The contents of this file are subject to the Mozilla Public
* License Version 1.1 (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/MPL/
*
* 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.org code.
*
* The Initial Developer of the Original Code is Brian Ryner.
* Portions created by Brian Ryner are Copyright (C) 2000 Brian Ryner.
* All Rights Reserved.
*
* Contributor(s):
* Scott MacGregor <mscott@netscape.com>
*/
#include "nsIconChannel.h"
#include "nsIconProtocolHandler.h"
#include "nsIURL.h"
#include "nsCRT.h"
#include "nsCOMPtr.h"
#include "nsIComponentManager.h"
#include "nsIServiceManager.h"
static NS_DEFINE_CID(kStandardURICID, NS_STANDARDURL_CID);
////////////////////////////////////////////////////////////////////////////////
nsIconProtocolHandler::nsIconProtocolHandler()
{
NS_INIT_REFCNT();
}
nsIconProtocolHandler::~nsIconProtocolHandler()
{}
NS_IMPL_ISUPPORTS2(nsIconProtocolHandler, nsIProtocolHandler, nsISupportsWeakReference)
////////////////////////////////////////////////////////////////////////////////
// nsIProtocolHandler methods:
NS_IMETHODIMP nsIconProtocolHandler::GetScheme(char* *result)
{
*result = nsCRT::strdup("icon");
if (!*result) return NS_ERROR_OUT_OF_MEMORY;
return NS_OK;
}
NS_IMETHODIMP nsIconProtocolHandler::GetDefaultPort(PRInt32 *result)
{
*result = 0;
return NS_OK;
}
NS_IMETHODIMP nsIconProtocolHandler::NewURI(const char *aSpec, nsIURI *aBaseURI, nsIURI **result)
{
nsresult rv;
// no concept of a relative icon url
NS_ASSERTION(!aBaseURI, "base url passed into icon protocol handler");
nsCOMPtr<nsIURI> url = do_CreateInstance(kStandardURICID, &rv);
if (NS_FAILED(rv)) return rv;
rv = url->SetSpec((char*)aSpec);
*result = url;
NS_IF_ADDREF(*result);
return rv;
}
NS_IMETHODIMP nsIconProtocolHandler::NewChannel(nsIURI* url, nsIChannel* *result)
{
nsCOMPtr<nsIChannel> channel;
NS_NEWXPCOM(channel, nsIconChannel);
if (channel)
NS_STATIC_CAST(nsIconChannel*,NS_STATIC_CAST(nsIChannel*, channel))->Init(url);
*result = channel;
NS_IF_ADDREF(*result);
return NS_OK;
}
////////////////////////////////////////////////////////////////////////////////

View File

@@ -0,0 +1,43 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 4 -*-
*
* The contents of this file are subject to the Netscape Public
* License Version 1.1 (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.org 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.
*
* Contributor(s):
* Scott MacGregor <mscott@netscape.com>
*/
#ifndef nsIconProtocolHandler_h___
#define nsIconProtocolHandler_h___
#include "nsWeakReference.h"
#include "nsIProtocolHandler.h"
class nsIconProtocolHandler : public nsIProtocolHandler, public nsSupportsWeakReference
{
public:
NS_DECL_ISUPPORTS
NS_DECL_NSIPROTOCOLHANDLER
// nsIconProtocolHandler methods:
nsIconProtocolHandler();
virtual ~nsIconProtocolHandler();
protected:
};
#endif /* nsIconProtocolHandler_h___ */

View File

@@ -0,0 +1,46 @@
#!gmake
#
# The contents of this file are subject to the Netscape Public
# License Version 1.1 (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.org 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.
#
# Contributor(s):
# Scott MacGregor <mscott@netscape.com>
DEPTH=..\..\..\..\..
MODULE=imgicon
LIBRARY_NAME=imgiconwin_s
CPP_OBJS=\
.\$(OBJDIR)\nsIconChannel.obj \
$(NULL)
INCS = $(INCS) \
-I$(DEPTH)\dist\include \
-I..\ \
$(NULL)
include <$(DEPTH)\config\rules.mak>
install:: $(LIBRARY)
$(MAKE_INSTALL) $(LIBRARY) $(DIST)\lib
clobber::
rm -f $(DIST)\lib\$(LIBRARY_NAME).lib

View File

@@ -0,0 +1,377 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 4 -*-
*
* The contents of this file are subject to the Mozilla Public
* License Version 1.1 (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/MPL/
*
* 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.org code.
*
* The Initial Developer of the Original Code is Brian Ryner.
* Portions created by Brian Ryner are Copyright (C) 2000 Brian Ryner.
* All Rights Reserved.
*
* Contributor(s):
* Scott MacGregor <mscott@netscape.com>
*/
#include "nsIconChannel.h"
#include "nsIServiceManager.h"
#include "nsIInterfaceRequestor.h"
#include "nsXPIDLString.h"
#include "nsMimeTypes.h"
#include "nsMemory.h"
#include "nsIStringStream.h"
#include "nsIURL.h"
#include "nsNetUtil.h"
// we need windows.h to read out registry information...
#include <windows.h>
#include <shellapi.h>
// nsIconChannel methods
nsIconChannel::nsIconChannel()
{
NS_INIT_REFCNT();
mStatus = NS_OK;
}
nsIconChannel::~nsIconChannel()
{}
NS_IMPL_THREADSAFE_ISUPPORTS2(nsIconChannel,
nsIChannel,
nsIRequest)
nsresult nsIconChannel::Init(nsIURI* uri)
{
nsresult rv;
NS_ASSERTION(uri, "no uri");
mUrl = uri;
return NS_OK;
}
////////////////////////////////////////////////////////////////////////////////
// nsIRequest methods:
NS_IMETHODIMP nsIconChannel::GetName(PRUnichar* *result)
{
return NS_ERROR_NOT_IMPLEMENTED;
}
NS_IMETHODIMP nsIconChannel::IsPending(PRBool *result)
{
NS_NOTREACHED("nsIconChannel::IsPending");
return NS_ERROR_NOT_IMPLEMENTED;
}
NS_IMETHODIMP nsIconChannel::GetStatus(nsresult *status)
{
*status = mStatus;
return NS_OK;
}
NS_IMETHODIMP nsIconChannel::Cancel(nsresult status)
{
NS_ASSERTION(NS_FAILED(status), "shouldn't cancel with a success code");
nsresult rv = NS_ERROR_FAILURE;
mStatus = status;
return rv;
}
NS_IMETHODIMP nsIconChannel::Suspend(void)
{
NS_NOTREACHED("nsIconChannel::Suspend");
return NS_ERROR_NOT_IMPLEMENTED;
}
NS_IMETHODIMP nsIconChannel::Resume(void)
{
NS_NOTREACHED("nsIconChannel::Resume");
return NS_ERROR_NOT_IMPLEMENTED;
}
////////////////////////////////////////////////////////////////////////////////
// nsIChannel methods:
NS_IMETHODIMP nsIconChannel::GetOriginalURI(nsIURI* *aURI)
{
*aURI = mOriginalURI ? mOriginalURI : mUrl;
NS_ADDREF(*aURI);
return NS_OK;
}
NS_IMETHODIMP nsIconChannel::SetOriginalURI(nsIURI* aURI)
{
mOriginalURI = aURI;
return NS_OK;
}
NS_IMETHODIMP nsIconChannel::GetURI(nsIURI* *aURI)
{
*aURI = mUrl;
NS_IF_ADDREF(*aURI);
return NS_OK;
}
NS_IMETHODIMP nsIconChannel::SetURI(nsIURI* aURI)
{
mUrl = aURI;
return NS_OK;
}
NS_IMETHODIMP
nsIconChannel::Open(nsIInputStream **_retval)
{
return NS_ERROR_FAILURE;
}
void InvertRows(unsigned char * aInitialBuffer, PRUint32 sizeOfBuffer, PRUint32 numBytesPerRow)
{
PRUint32 numRows = sizeOfBuffer / numBytesPerRow;
void * temporaryRowHolder = (void *) nsMemory::Alloc(numBytesPerRow);
PRUint32 currentRow = 0;
PRUint32 lastRow = (numRows - 1) * numBytesPerRow;
while (currentRow < lastRow)
{
// store the current row into a temporary buffer
nsCRT::memcpy(temporaryRowHolder, (void *) &aInitialBuffer[currentRow], numBytesPerRow);
nsCRT::memcpy((void *) &aInitialBuffer[currentRow], (void *)&aInitialBuffer[lastRow], numBytesPerRow);
nsCRT::memcpy((void *) &aInitialBuffer[lastRow], temporaryRowHolder, numBytesPerRow);
lastRow -= numBytesPerRow;
currentRow += numBytesPerRow;
}
}
NS_IMETHODIMP nsIconChannel::AsyncOpen(nsIStreamListener *aListener, nsISupports *ctxt)
{
// get the file name from the url
nsXPIDLCString fileName; // will contain a dummy file we'll use to figure out the type of icon desired.
nsXPIDLCString filePath; // will contain an optional parameter for small vs. large icon. default is small
mUrl->GetHost(getter_Copies(fileName));
nsCOMPtr<nsIURL> url (do_QueryInterface(mUrl));
if (url)
url->GetFileBaseName(getter_Copies(filePath));
// 1) get a hIcon for the file.
SHFILEINFO sfi;
UINT infoFlags = SHGFI_USEFILEATTRIBUTES | SHGFI_ICON;
if (filePath && !nsCRT::strcmp(filePath, "large"))
infoFlags |= SHGFI_LARGEICON;
else // default to small
infoFlags |= SHGFI_SMALLICON;
LONG result= SHGetFileInfo(fileName, FILE_ATTRIBUTE_ARCHIVE, &sfi, sizeof(sfi), infoFlags);
if (result > 0 && sfi.hIcon)
{
// we got a handle to an icon. Now we want to get a bitmap for the icon using GetIconInfo....
ICONINFO pIconInfo;
result = GetIconInfo(sfi.hIcon, &pIconInfo);
if (result > 0)
{
// now we have the bit map we need to get info about the bitmap
BITMAPINFO pBitMapInfo;
BITMAPINFOHEADER pBitMapInfoHeader;
pBitMapInfo.bmiHeader.biBitCount = 0;
pBitMapInfo.bmiHeader.biSize = sizeof(pBitMapInfoHeader);
HDC pDC = CreateCompatibleDC(NULL); // get a device context for the screen.
result = GetDIBits(pDC, pIconInfo.hbmColor, 0, 0, NULL, &pBitMapInfo, DIB_RGB_COLORS);
if (result > 0 && pBitMapInfo.bmiHeader.biSizeImage > 0)
{
// allocate a buffer to hold the bit map....this should be a buffer that's biSizeImage...
unsigned char * buffer = (PRUint8 *) nsMemory::Alloc(pBitMapInfo.bmiHeader.biSizeImage);
result = GetDIBits(pDC, pIconInfo.hbmColor, 0, pBitMapInfo.bmiHeader.biHeight, (void *) buffer, &pBitMapInfo, DIB_RGB_COLORS);
if (result > 0)
{
PRUint32 bytesPerPixel = pBitMapInfo.bmiHeader.biBitCount / 8;
InvertRows(buffer, pBitMapInfo.bmiHeader.biSizeImage, pBitMapInfo.bmiHeader.biWidth * bytesPerPixel);
// Convert our little icon buffer which is padded to 4 bytes per pixel into a nice 3 byte per pixel
// description.
nsCString iconBuffer;
iconBuffer.Assign((char) pBitMapInfo.bmiHeader.biWidth);
iconBuffer.Append((char) pBitMapInfo.bmiHeader.biHeight);
PRInt32 index = 0;
if (pBitMapInfo.bmiHeader.biBitCount == 16)
{
PRUint8 redValue, greenValue, blueValue, partialGreen;
while (index < pBitMapInfo.bmiHeader.biSizeImage)
{
DWORD dst=(DWORD) buffer[index];
PRUint16 num = 0;
num = (PRUint8) buffer[index];
num <<= 8;
num |= (PRUint8) buffer[index+1];
//blueValue = (PRUint8)((*dst)&(0x1F));
//greenValue = (PRUint8)(((*dst)>>5)&(0x1F));
//redValue = (PRUint8)(((*dst)>>10)&(0x1F));
redValue = ((PRUint32) (((float)(num & 0x7c00) / 0x7c00) * 0xFF0000) & 0xFF0000)>> 16;
greenValue = ((PRUint32)(((float)(num & 0x03E0) / 0x03E0) * 0x00FF00) & 0x00FF00)>> 8;
blueValue = ((PRUint32)(((float)(num & 0x001F) / 0x001F) * 0x0000FF) & 0x0000FF);
// now we have the right RGB values...
iconBuffer.Append((char) redValue);
iconBuffer.Append((char) greenValue);
iconBuffer.Append((char) blueValue);
index += bytesPerPixel;
}
}
else
{
while (index <pBitMapInfo.bmiHeader.biSizeImage)
{
iconBuffer.Append((char) buffer[index]);
iconBuffer.Append((char) buffer[index+1]);
iconBuffer.Append((char) buffer[index+2]);
index += bytesPerPixel;
}
}
// now we need to tack on the alpha data...which is hbmMask
pBitMapInfo.bmiHeader.biBitCount = 0;
pBitMapInfo.bmiHeader.biSize = sizeof(pBitMapInfoHeader);
result = GetDIBits(pDC, pIconInfo.hbmMask, 0, 0, NULL, &pBitMapInfo, DIB_RGB_COLORS);
if (result > 0 && pBitMapInfo.bmiHeader.biSizeImage > 0)
{
// allocate a buffer to hold the bit map....this should be a buffer that's biSizeImage...
unsigned char * maskBuffer = (PRUint8 *) nsMemory::Alloc(pBitMapInfo.bmiHeader.biSizeImage);
result = GetDIBits(pDC, pIconInfo.hbmMask, 0, pBitMapInfo.bmiHeader.biHeight, (void *) maskBuffer, &pBitMapInfo, DIB_RGB_COLORS);
if (result > 0)
{
InvertRows(maskBuffer, pBitMapInfo.bmiHeader.biSizeImage, 4);
index = 0;
// for some reason the bit mask on windows are flipped from the values we really want for transparency.
// So complement each byte in the bit mask.
while (index < pBitMapInfo.bmiHeader.biSizeImage)
{
maskBuffer[index]^=255;
index += 1;
}
iconBuffer.Append((char *) maskBuffer, pBitMapInfo.bmiHeader.biSizeImage);
}
nsMemory::Free(maskBuffer);
} // if we have a mask buffer to apply
// turn our nsString into a stream looking object...
aListener->OnStartRequest(this, ctxt);
// turn our string into a stream...
nsCOMPtr<nsISupports> streamSupports;
NS_NewByteInputStream(getter_AddRefs(streamSupports), iconBuffer.get(), iconBuffer.Length());
nsCOMPtr<nsIInputStream> inputStr (do_QueryInterface(streamSupports));
aListener->OnDataAvailable(this, ctxt, inputStr, 0, iconBuffer.Length());
aListener->OnStopRequest(this, ctxt, NS_OK, nsnull);
} // if we got valid bits for the main bitmap mask
nsMemory::Free(buffer);
}
DeleteDC(pDC);
}
}
return NS_OK;
}
NS_IMETHODIMP nsIconChannel::GetLoadAttributes(PRUint32 *aLoadAttributes)
{
*aLoadAttributes = mLoadAttributes;
return NS_OK;
}
NS_IMETHODIMP nsIconChannel::SetLoadAttributes(PRUint32 aLoadAttributes)
{
mLoadAttributes = aLoadAttributes;
return NS_OK;
}
NS_IMETHODIMP nsIconChannel::GetContentType(char* *aContentType)
{
if (!aContentType) return NS_ERROR_NULL_POINTER;
*aContentType = nsCRT::strdup("image/icon");
if (!*aContentType) return NS_ERROR_OUT_OF_MEMORY;
return NS_OK;
}
NS_IMETHODIMP
nsIconChannel::SetContentType(const char *aContentType)
{
//It doesn't make sense to set the content-type on this type
// of channel...
return NS_ERROR_FAILURE;
}
NS_IMETHODIMP nsIconChannel::GetContentLength(PRInt32 *aContentLength)
{
*aContentLength = mContentLength;
return NS_OK;
}
NS_IMETHODIMP nsIconChannel::SetContentLength(PRInt32 aContentLength)
{
NS_NOTREACHED("nsIconChannel::SetContentLength");
return NS_ERROR_NOT_IMPLEMENTED;
}
NS_IMETHODIMP nsIconChannel::GetLoadGroup(nsILoadGroup* *aLoadGroup)
{
*aLoadGroup = mLoadGroup;
NS_IF_ADDREF(*aLoadGroup);
return NS_OK;
}
NS_IMETHODIMP nsIconChannel::SetLoadGroup(nsILoadGroup* aLoadGroup)
{
mLoadGroup = aLoadGroup;
return NS_OK;
}
NS_IMETHODIMP nsIconChannel::GetOwner(nsISupports* *aOwner)
{
*aOwner = mOwner.get();
NS_IF_ADDREF(*aOwner);
return NS_OK;
}
NS_IMETHODIMP nsIconChannel::SetOwner(nsISupports* aOwner)
{
mOwner = aOwner;
return NS_OK;
}
NS_IMETHODIMP nsIconChannel::GetNotificationCallbacks(nsIInterfaceRequestor* *aNotificationCallbacks)
{
*aNotificationCallbacks = mCallbacks.get();
NS_IF_ADDREF(*aNotificationCallbacks);
return NS_OK;
}
NS_IMETHODIMP nsIconChannel::SetNotificationCallbacks(nsIInterfaceRequestor* aNotificationCallbacks)
{
mCallbacks = aNotificationCallbacks;
return NS_OK;
}
NS_IMETHODIMP nsIconChannel::GetSecurityInfo(nsISupports * *aSecurityInfo)
{
*aSecurityInfo = nsnull;
return NS_OK;
}

View File

@@ -0,0 +1,56 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 4 -*-
*
* The contents of this file are subject to the Mozilla Public
* License Version 1.1 (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/MPL/
*
* 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.org code.
*
* The Initial Developer of the Original Code is Brian Ryner.
* Portions created by Brian Ryner are Copyright (C) 2000 Brian Ryner.
* All Rights Reserved.
*
* Contributor(s):
* Scott MacGregor <mscott@netscape.com>
*/
#ifndef nsIconChannel_h___
#define nsIconChannel_h___
#include "nsCOMPtr.h"
#include "nsXPIDLString.h"
#include "nsIChannel.h"
#include "nsILoadGroup.h"
#include "nsIInterfaceRequestor.h"
#include "nsIURI.h"
class nsIconChannel : public nsIChannel
{
public:
NS_DECL_ISUPPORTS
NS_DECL_NSIREQUEST
NS_DECL_NSICHANNEL
nsIconChannel();
virtual ~nsIconChannel();
nsresult Init(nsIURI* uri);
protected:
nsCOMPtr<nsIURI> mUrl;
nsCOMPtr<nsIURI> mOriginalURI;
PRUint32 mLoadAttributes;
PRInt32 mContentLength;
nsCOMPtr<nsILoadGroup> mLoadGroup;
nsCOMPtr<nsIInterfaceRequestor> mCallbacks;
nsCOMPtr<nsISupports> mOwner;
nsresult mStatus;
};
#endif /* nsIconChannel_h___ */

View File

@@ -0,0 +1,42 @@
#
# The contents of this file are subject to the Mozilla Public
# License Version 1.1 (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/MPL/
#
# 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.org code
#
# The Initial Developer of the Original Code is Netscape
# Communications Corporation. Portions created by Netscape are
# Copyright (C) 2001 Netscape Communications Corporation. All
# Rights Reserved.
#
# Contributor(s):
#
DEPTH = ../../../..
topsrcdir = @top_srcdir@
srcdir = @srcdir@
VPATH = @srcdir@
include $(DEPTH)/config/autoconf.mk
MODULE = imgjpeg
LIBRARY_NAME = imgjpeg
IS_COMPONENT = 1
REQUIRES = xpcom string necko layout jpeg gfx2 imglib2
CPPSRCS = nsJPEGDecoder.cpp nsJPEGFactory.cpp
EXTRA_DSO_LDOPTS = $(JPEG_LIBS) $(ZLIB_LIBS) \
$(MOZ_COMPONENT_LIBS) \
$(NULL)
include $(topsrcdir)/config/rules.mk

View File

@@ -0,0 +1,52 @@
#!nmake
#
# The contents of this file are subject to the Mozilla Public
# License Version 1.1 (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/MPL/
#
# 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.org code
#
# The Initial Developer of the Original Code is Netscape
# Communications Corporation. Portions created by Netscape are
# Copyright (C) 2001 Netscape Communications Corporation. All
# Rights Reserved.
#
# Contributor(s):
# Stuart Parmenter <pavlov@netscape.com>
#
DEPTH=..\..\..\..
include <$(DEPTH)/config/config.mak>
MODULE = imgjpeg
LIBRARY_NAME = imgjpeg
DLL = $(OBJDIR)\$(LIBRARY_NAME).dll
MAKE_OBJ_TYPE = DLL
OBJS = \
.\$(OBJDIR)\nsJPEGDecoder.obj \
.\$(OBJDIR)\nsJPEGFactory.obj \
$(NULL)
LLIBS=\
$(LIBNSPR) \
$(DIST)\lib\jpeg3250.lib \
$(DIST)\lib\xpcom.lib \
$(DIST)\lib\gkgfxwin.lib \
$(NULL)
include <$(DEPTH)\config\rules.mak>
install:: $(DLL)
$(MAKE_INSTALL) .\$(OBJDIR)\$(LIBRARY_NAME).dll $(DIST)\bin\components
$(MAKE_INSTALL) .\$(OBJDIR)\$(LIBRARY_NAME).lib $(DIST)\lib
clobber::
rm -f $(DIST)\bin\components\$(LIBRARY_NAME).dll
rm -f $(DIST)\lib\$(LIBRARY_NAME).lib

View File

@@ -0,0 +1,829 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
*
* The contents of this file are subject to the Mozilla Public
* License Version 1.1 (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/MPL/
*
* 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.org code.
*
* The Initial Developer of the Original Code is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 2001 Netscape Communications Corporation.
* All Rights Reserved.
*
* Contributor(s):
* Stuart Parmenter <pavlov@netscape.com>
*
*/
#include "nsJPEGDecoder.h"
#include "nsIInputStream.h"
#include "nspr.h"
#include "nsCRT.h"
#include "nsIComponentManager.h"
#include "imgIContainerObserver.h"
#include "ImageLogging.h"
NS_IMPL_ISUPPORTS2(nsJPEGDecoder, imgIDecoder, nsIOutputStream)
#if defined(PR_LOGGING)
PRLogModuleInfo *gJPEGlog = PR_NewLogModule("JPEGDecoder");
#else
#define gJPEGlog
#endif
void PR_CALLBACK init_source (j_decompress_ptr jd);
boolean PR_CALLBACK fill_input_buffer (j_decompress_ptr jd);
void PR_CALLBACK skip_input_data (j_decompress_ptr jd, long num_bytes);
void PR_CALLBACK term_source (j_decompress_ptr jd);
void PR_CALLBACK my_error_exit (j_common_ptr cinfo);
/* Normal JFIF markers can't have more bytes than this. */
#define MAX_JPEG_MARKER_LENGTH (((PRUint32)1 << 16) - 1)
/* Possible states for JPEG source manager */
enum data_source_state {
READING_BACK = 0, /* Must be zero for init purposes */
READING_NEW
};
/*
* Implementation of a JPEG src object that understands our state machine
*/
typedef struct {
/* public fields; must be first in this struct! */
struct jpeg_source_mgr pub;
nsJPEGDecoder *decoder;
} decoder_source_mgr;
nsJPEGDecoder::nsJPEGDecoder()
{
NS_INIT_ISUPPORTS();
mState = JPEG_HEADER;
mFillState = READING_BACK;
mSamples = nsnull;
mSamples3 = nsnull;
mRGBPadRow = nsnull;
mRGBPadRowLength = 0;
mBytesToSkip = 0;
memset(&mInfo, 0, sizeof(jpeg_decompress_struct));
mCompletedPasses = 0;
mBuffer = nsnull;
mBufferLen = mBufferSize = 0;
mBackBuffer = nsnull;
mBackBufferLen = mBackBufferSize = mBackBufferUnreadLen = 0;
}
nsJPEGDecoder::~nsJPEGDecoder()
{
if (mBuffer)
PR_Free(mBuffer);
if (mBackBuffer)
PR_Free(mBackBuffer);
if (mRGBPadRow)
PR_Free(mRGBPadRow);
}
/** imgIDecoder methods **/
/* void init (in imgIRequest aRequest); */
NS_IMETHODIMP nsJPEGDecoder::Init(imgIRequest *aRequest)
{
mRequest = aRequest;
mObserver = do_QueryInterface(mRequest);
aRequest->GetImage(getter_AddRefs(mImage));
/* We set up the normal JPEG error routines, then override error_exit. */
mInfo.err = jpeg_std_error(&mErr.pub);
/* mInfo.err = jpeg_std_error(&mErr.pub); */
mErr.pub.error_exit = my_error_exit;
/* Establish the setjmp return context for my_error_exit to use. */
if (setjmp(mErr.setjmp_buffer)) {
/* If we get here, the JPEG code has signaled an error.
* We need to clean up the JPEG object, close the input file, and return.
*/
return NS_ERROR_FAILURE;
}
/* Step 1: allocate and initialize JPEG decompression object */
jpeg_create_decompress(&mInfo);
decoder_source_mgr *src;
if (mInfo.src == NULL) {
//mInfo.src = PR_NEWZAP(decoder_source_mgr);
src = PR_NEWZAP(decoder_source_mgr);
if (!src) {
return PR_FALSE;
}
mInfo.src = (struct jpeg_source_mgr *) src;
}
/* Step 2: specify data source (eg, a file) */
/* Setup callback functions. */
src->pub.init_source = init_source;
src->pub.fill_input_buffer = fill_input_buffer;
src->pub.skip_input_data = skip_input_data;
src->pub.resync_to_restart = jpeg_resync_to_restart;
src->pub.term_source = term_source;
src->decoder = this;
return NS_OK;
}
/* readonly attribute imgIRequest request; */
NS_IMETHODIMP nsJPEGDecoder::GetRequest(imgIRequest * *aRequest)
{
*aRequest = mRequest;
NS_ADDREF(*aRequest);
return NS_OK;
}
/** nsIOutputStream methods **/
/* void close (); */
NS_IMETHODIMP nsJPEGDecoder::Close()
{
PR_LOG(gJPEGlog, PR_LOG_DEBUG,
("[this=%p] nsJPEGDecoder::Close\n", this));
if (mState != JPEG_DONE && mState != JPEG_SINK_NON_JPEG_TRAILER)
NS_WARNING("Never finished decoding the JPEG.");
/* Step 8: Release JPEG decompression object */
/* This is an important step since it will release a good deal of memory. */
jpeg_destroy_decompress(&mInfo);
return NS_OK;
}
/* void flush (); */
NS_IMETHODIMP nsJPEGDecoder::Flush()
{
LOG_SCOPE(gJPEGlog, "nsJPEGDecoder::Flush");
PRUint32 ret;
if (mState != JPEG_DONE && mState != JPEG_SINK_NON_JPEG_TRAILER)
return this->WriteFrom(nsnull, 0, &ret);
return NS_OK;
}
/* unsigned long write (in string buf, in unsigned long count); */
NS_IMETHODIMP nsJPEGDecoder::Write(const char *buf, PRUint32 count, PRUint32 *_retval)
{
return NS_ERROR_NOT_IMPLEMENTED;
}
/* unsigned long writeFrom (in nsIInputStream inStr, in unsigned long count); */
NS_IMETHODIMP nsJPEGDecoder::WriteFrom(nsIInputStream *inStr, PRUint32 count, PRUint32 *_retval)
{
LOG_SCOPE_WITH_PARAM(gJPEGlog, "nsJPEGDecoder::WriteFrom", "count", count);
/* We use our private extension JPEG error handler.
* Note that this struct must live as long as the main JPEG parameter
* struct, to avoid dangling-pointer problems.
*/
// XXX above what is this?
if (inStr) {
if (!mBuffer) {
mBuffer = (JOCTET *)PR_Malloc(count);
mBufferSize = count;
} else if (count > mBufferSize) {
mBuffer = (JOCTET *)PR_Realloc(mBuffer, count);
mBufferSize = count;
}
nsresult rv = inStr->Read((char*)mBuffer, count, &mBufferLen);
*_retval = mBufferLen;
//nsresult rv = mOutStream->WriteFrom(inStr, count, _retval);
NS_ASSERTION(NS_SUCCEEDED(rv), "nsJPEGDecoder::WriteFrom -- mOutStream->WriteFrom failed");
}
// else no input stream.. Flush() ?
nsresult error_code = NS_ERROR_FAILURE;
/* Return here if there is a fatal error. */
if ((error_code = setjmp(mErr.setjmp_buffer)) != 0) {
return error_code;
}
PR_LOG(gJPEGlog, PR_LOG_DEBUG,
("[this=%p] nsJPEGDecoder::WriteFrom -- processing JPEG data\n", this));
decoder_source_mgr *src = NS_REINTERPRET_CAST(decoder_source_mgr *, mInfo.src);
switch (mState) {
case JPEG_HEADER:
{
LOG_SCOPE(gJPEGlog, "nsJPEGDecoder::WriteFrom -- entering JPEG_HEADER case");
/* Step 3: read file parameters with jpeg_read_header() */
if (jpeg_read_header(&mInfo, TRUE) == JPEG_SUSPENDED)
return NS_OK; /* I/O suspension */
/*
* Don't allocate a giant and superfluous memory buffer
* when the image is a sequential JPEG.
*/
mInfo.buffered_image = jpeg_has_multiple_scans(&mInfo);
/* Used to set up image size so arrays can be allocated */
jpeg_calc_output_dimensions(&mInfo);
mObserver->OnStartDecode(nsnull, nsnull);
mImage->Init(mInfo.image_width, mInfo.image_height, mObserver);
mObserver->OnStartContainer(nsnull, nsnull, mImage);
mFrame = do_CreateInstance("@mozilla.org/gfx/image/frame;2");
gfx_format format;
#ifdef XP_PC
format = gfxIFormats::BGR;
#else
format = gfxIFormats::RGB;
#endif
mFrame->Init(0, 0, mInfo.image_width, mInfo.image_height, format);
mImage->AppendFrame(mFrame);
mObserver->OnStartFrame(nsnull, nsnull, mFrame);
/*
* Make a one-row-high sample array that will go away
* when done with image. Always make it big enough to
* hold an RGB row. Since this uses the IJG memory
* manager, it must be allocated before the call to
* jpeg_start_compress().
*/
int row_stride;
if(mInfo.output_components == 1)
row_stride = mInfo.output_width;
else
row_stride = mInfo.output_width * 4; // use 4 instead of mInfo.output_components
// so we don't have to fuss with byte alignment.
// Mac wants 4 anyways.
mSamples = (*mInfo.mem->alloc_sarray)((j_common_ptr) &mInfo,
JPOOL_IMAGE,
row_stride, 1);
#if defined(XP_PC) || defined(XP_MAC)
// allocate buffer to do byte flipping if needed
if (mInfo.output_components == 3) {
mRGBPadRow = (PRUint8*) PR_MALLOC(row_stride);
mRGBPadRowLength = row_stride;
memset(mRGBPadRow, 0, mRGBPadRowLength);
}
#endif
/* Allocate RGB buffer for conversion from greyscale. */
if (mInfo.output_components != 3) {
row_stride = mInfo.output_width * 4;
mSamples3 = (*mInfo.mem->alloc_sarray)((j_common_ptr) &mInfo,
JPOOL_IMAGE,
row_stride, 1);
}
mState = JPEG_START_DECOMPRESS;
}
case JPEG_START_DECOMPRESS:
{
LOG_SCOPE(gJPEGlog, "nsJPEGDecoder::WriteFrom -- entering JPEG_START_DECOMPRESS case");
/* Step 4: set parameters for decompression */
/* FIXME -- Should reset dct_method and dither mode
* for final pass of progressive JPEG
*/
mInfo.dct_method = JDCT_FASTEST;
mInfo.dither_mode = JDITHER_ORDERED;
mInfo.do_fancy_upsampling = FALSE;
mInfo.enable_2pass_quant = FALSE;
mInfo.do_block_smoothing = TRUE;
/* Step 5: Start decompressor */
if (jpeg_start_decompress(&mInfo) == FALSE)
return NS_OK; /* I/O suspension */
/* If this is a progressive JPEG ... */
if (mInfo.buffered_image) {
mState = JPEG_DECOMPRESS_PROGRESSIVE;
} else {
mState = JPEG_DECOMPRESS_SEQUENTIAL;
}
}
case JPEG_DECOMPRESS_SEQUENTIAL:
{
if (mState == JPEG_DECOMPRESS_SEQUENTIAL)
{
LOG_SCOPE(gJPEGlog, "nsJPEGDecoder::WriteFrom -- JPEG_DECOMPRESS_SEQUENTIAL case");
if (OutputScanlines(-1) == PR_FALSE)
return NS_OK; /* I/O suspension */
/* If we've completed image output ... */
NS_ASSERTION(mInfo.output_scanline == mInfo.output_height, "We didn't process all of the data!");
mState = JPEG_DONE;
}
}
case JPEG_DECOMPRESS_PROGRESSIVE:
{
if (mState == JPEG_DECOMPRESS_PROGRESSIVE)
{
LOG_SCOPE(gJPEGlog, "nsJPEGDecoder::WriteFrom -- JPEG_DECOMPRESS_PROGRESSIVE case");
int status;
do {
status = jpeg_consume_input(&mInfo);
} while (!((status == JPEG_SUSPENDED) ||
(status == JPEG_REACHED_EOI)));
switch (status) {
case JPEG_REACHED_EOI:
// End of image
mState = JPEG_FINAL_PROGRESSIVE_SCAN_OUTPUT;
break;
case JPEG_SUSPENDED:
PR_LOG(gJPEGlog, PR_LOG_DEBUG,
("[this=%p] nsJPEGDecoder::WriteFrom -- suspending\n", this));
return NS_OK; /* I/O suspension */
default:
printf("got someo other state!?\n");
}
}
}
case JPEG_FINAL_PROGRESSIVE_SCAN_OUTPUT:
{
if (mState == JPEG_FINAL_PROGRESSIVE_SCAN_OUTPUT)
{
LOG_SCOPE(gJPEGlog, "nsJPEGDecoder::WriteFrom -- entering JPEG_FINAL_PROGRESSIVE_SCAN_OUTPUT case");
// XXX progressive? ;)
// not really progressive according to the state machine... -saari
jpeg_start_output(&mInfo, mInfo.input_scan_number);
if (OutputScanlines(-1) == PR_FALSE)
return NS_OK; /* I/O suspension */
jpeg_finish_output(&mInfo);
mState = JPEG_DONE;
}
}
case JPEG_DONE:
{
LOG_SCOPE(gJPEGlog, "nsJPEGDecoder::WriteFrom -- entering JPEG_DONE case");
/* Step 7: Finish decompression */
if (jpeg_finish_decompress(&mInfo) == FALSE)
return NS_OK; /* I/O suspension */
mState = JPEG_SINK_NON_JPEG_TRAILER;
/* we're done dude */
break;
}
case JPEG_SINK_NON_JPEG_TRAILER:
PR_LOG(gJPEGlog, PR_LOG_DEBUG,
("[this=%p] nsJPEGDecoder::WriteFrom -- entering JPEG_SINK_NON_JPEG_TRAILER case\n", this));
break;
}
return NS_OK;
}
int
nsJPEGDecoder::OutputScanlines(int num_scanlines)
{
int pass = 0;
if (mState == JPEG_FINAL_PROGRESSIVE_SCAN_OUTPUT)
pass = -1;
else
pass = mCompletedPasses + 1;
while ((mInfo.output_scanline < mInfo.output_height) && num_scanlines--) {
JSAMPROW samples;
/* Request one scanline. Returns 0 or 1 scanlines. */
int ns = jpeg_read_scanlines(&mInfo, mSamples, 1);
if (ns != 1) {
return PR_FALSE; /* suspend */
}
/* If grayscale image ... */
if (mInfo.output_components == 1) {
JSAMPLE j;
JSAMPLE *j1 = mSamples[0];
const JSAMPLE *j1end = j1 + mInfo.output_width;
JSAMPLE *j3 = mSamples3[0];
/* Convert from grayscale to RGB. */
while (j1 < j1end) {
#ifdef XP_MAC
j = *j1++;
j3[0] = 0;
j3[1] = j;
j3[2] = j;
j3[3] = j;
j3 += 4;
#else
j = *j1++;
j3[0] = j;
j3[1] = j;
j3[2] = j;
j3 += 3;
#endif
}
samples = mSamples3[0];
} else {
/* 24-bit color image */
#ifdef XP_PC
memset(mRGBPadRow, 0, mInfo.output_width * 4);
PRUint8 *ptrOutputBuf = mRGBPadRow;
JSAMPLE *j1 = mSamples[0];
for (PRUint32 i=0;i<mInfo.output_width;++i) {
ptrOutputBuf[2] = *j1++;
ptrOutputBuf[1] = *j1++;
ptrOutputBuf[0] = *j1++;
ptrOutputBuf += 3;
}
samples = mRGBPadRow;
#else
#ifdef XP_MAC
memset(mRGBPadRow, 0, mInfo.output_width * 4);
PRUint8 *ptrOutputBuf = mRGBPadRow;
JSAMPLE *j1 = mSamples[0];
for (PRUint32 i=0;i<mInfo.output_width;++i) {
ptrOutputBuf[0] = 0;
ptrOutputBuf[1] = *j1++;
ptrOutputBuf[2] = *j1++;
ptrOutputBuf[3] = *j1++;
ptrOutputBuf += 4;
}
samples = mRGBPadRow;
#else
samples = mSamples[0];
#endif
#endif
}
PRUint32 bpr;
mFrame->GetImageBytesPerRow(&bpr);
mFrame->SetImageData(
samples, // data
bpr, // length
(mInfo.output_scanline-1) * bpr); // offset
nsRect r(0, mInfo.output_scanline, mInfo.output_width, 1);
mObserver->OnDataAvailable(nsnull, nsnull, mFrame, &r);
}
return PR_TRUE;
}
/* [noscript] unsigned long writeSegments (in nsReadSegmentFun reader, in voidPtr closure, in unsigned long count); */
NS_IMETHODIMP nsJPEGDecoder::WriteSegments(nsReadSegmentFun reader, void * closure, PRUint32 count, PRUint32 *_retval)
{
return NS_ERROR_NOT_IMPLEMENTED;
}
/* attribute boolean nonBlocking; */
NS_IMETHODIMP nsJPEGDecoder::GetNonBlocking(PRBool *aNonBlocking)
{
return NS_ERROR_NOT_IMPLEMENTED;
}
NS_IMETHODIMP nsJPEGDecoder::SetNonBlocking(PRBool aNonBlocking)
{
return NS_ERROR_NOT_IMPLEMENTED;
}
/* attribute nsIOutputStreamObserver observer; */
NS_IMETHODIMP nsJPEGDecoder::GetObserver(nsIOutputStreamObserver * *aObserver)
{
return NS_ERROR_NOT_IMPLEMENTED;
}
NS_IMETHODIMP nsJPEGDecoder::SetObserver(nsIOutputStreamObserver * aObserver)
{
return NS_ERROR_NOT_IMPLEMENTED;
}
/* Override the standard error method in the IJG JPEG decoder code. */
void PR_CALLBACK
my_error_exit (j_common_ptr cinfo)
{
nsresult error_code = NS_ERROR_FAILURE;
decoder_error_mgr *err = (decoder_error_mgr *) cinfo->err;
#if 0
#ifdef DEBUG
/*ptn fix later */
if (il_debug >= 1) {
char buffer[JMSG_LENGTH_MAX];
/* Create the message */
(*cinfo->err->format_message) (cinfo, buffer);
ILTRACE(1,("%s\n", buffer));
}
#endif
/* Convert error to a browser error code */
if (cinfo->err->msg_code == JERR_OUT_OF_MEMORY)
error_code = MK_OUT_OF_MEMORY;
else
error_code = MK_IMAGE_LOSSAGE;
#endif
char buffer[JMSG_LENGTH_MAX];
/* Create the message */
(*cinfo->err->format_message) (cinfo, buffer);
fprintf(stderr, "my_error_exit()\n%s\n", buffer);
/* Return control to the setjmp point. */
longjmp(err->setjmp_buffer, error_code);
}
/******************************************************************************/
/*-----------------------------------------------------------------------------
* This is the callback routine from the IJG JPEG library used to supply new
* data to the decompressor when its input buffer is exhausted. It juggles
* multiple buffers in an attempt to avoid unnecessary copying of input data.
*
* (A simpler scheme is possible: It's much easier to use only a single
* buffer; when fill_input_buffer() is called, move any unconsumed data
* (beyond the current pointer/count) down to the beginning of this buffer and
* then load new data into the remaining buffer space. This approach requires
* a little more data copying but is far easier to get right.)
*
* At any one time, the JPEG decompressor is either reading from the necko
* input buffer, which is volatile across top-level calls to the IJG library,
* or the "backtrack" buffer. The backtrack buffer contains the remaining
* unconsumed data from the necko buffer after parsing was suspended due
* to insufficient data in some previous call to the IJG library.
*
* When suspending, the decompressor will back up to a convenient restart
* point (typically the start of the current MCU). The variables
* next_input_byte & bytes_in_buffer indicate where the restart point will be
* if the current call returns FALSE. Data beyond this point must be
* rescanned after resumption, so it must be preserved in case the decompressor
* decides to backtrack.
*
* Returns:
* TRUE if additional data is available, FALSE if no data present and
* the JPEG library should therefore suspend processing of input stream
*---------------------------------------------------------------------------*/
/******************************************************************************/
/* data source manager method
/******************************************************************************/
/******************************************************************************/
/* data source manager method
Initialize source. This is called by jpeg_read_header() before any
data is actually read. May leave
bytes_in_buffer set to 0 (in which case a fill_input_buffer() call
will occur immediately).
*/
void PR_CALLBACK
init_source (j_decompress_ptr jd)
{
}
/******************************************************************************/
/* data source manager method
Skip num_bytes worth of data. The buffer pointer and count should
be advanced over num_bytes input bytes, refilling the buffer as
needed. This is used to skip over a potentially large amount of
uninteresting data (such as an APPn marker). In some applications
it may be possible to optimize away the reading of the skipped data,
but it's not clear that being smart is worth much trouble; large
skips are uncommon. bytes_in_buffer may be zero on return.
A zero or negative skip count should be treated as a no-op.
*/
void PR_CALLBACK
skip_input_data (j_decompress_ptr jd, long num_bytes)
{
decoder_source_mgr *src = (decoder_source_mgr *)jd->src;
if (num_bytes > (long)src->pub.bytes_in_buffer) {
/*
* Can't skip it all right now until we get more data from
* network stream. Set things up so that fill_input_buffer
* will skip remaining amount.
*/
src->decoder->mBytesToSkip = (size_t)num_bytes - src->pub.bytes_in_buffer;
src->pub.next_input_byte += src->pub.bytes_in_buffer;
src->pub.bytes_in_buffer = 0;
} else {
/* Simple case. Just advance buffer pointer */
src->pub.bytes_in_buffer -= (size_t)num_bytes;
src->pub.next_input_byte += num_bytes;
}
}
/******************************************************************************/
/* data source manager method
This is called whenever bytes_in_buffer has reached zero and more
data is wanted. In typical applications, it should read fresh data
into the buffer (ignoring the current state of next_input_byte and
bytes_in_buffer), reset the pointer & count to the start of the
buffer, and return TRUE indicating that the buffer has been reloaded.
It is not necessary to fill the buffer entirely, only to obtain at
least one more byte. bytes_in_buffer MUST be set to a positive value
if TRUE is returned. A FALSE return should only be used when I/O
suspension is desired.
*/
boolean PR_CALLBACK
fill_input_buffer (j_decompress_ptr jd)
{
decoder_source_mgr *src = (decoder_source_mgr *)jd->src;
unsigned char *new_buffer = (unsigned char *)src->decoder->mBuffer;
PRUint32 new_buflen = src->decoder->mBufferLen;
PRUint32 bytesToSkip = src->decoder->mBytesToSkip;
switch(src->decoder->mFillState) {
case READING_BACK:
{
if (!new_buffer || new_buflen == 0)
return PR_FALSE; /* suspend */
src->decoder->mBufferLen = 0;
if (bytesToSkip != 0) {
if (bytesToSkip < new_buflen) {
/* All done skipping bytes; Return what's left. */
new_buffer += bytesToSkip;
new_buflen -= bytesToSkip;
src->decoder->mBytesToSkip = 0;
} else {
/* Still need to skip some more data in the future */
src->decoder->mBytesToSkip -= (size_t)new_buflen;
return PR_FALSE; /* suspend */
}
}
src->decoder->mBackBufferUnreadLen = src->pub.bytes_in_buffer;
src->pub.next_input_byte = new_buffer;
src->pub.bytes_in_buffer = (size_t)new_buflen;
src->decoder->mFillState = READING_NEW;
return PR_TRUE;
}
break;
case READING_NEW:
{
if (src->pub.next_input_byte != src->decoder->mBuffer) {
/* Backtrack data has been permanently consumed. */
src->decoder->mBackBufferUnreadLen = 0;
src->decoder->mBackBufferLen = 0;
}
/* Save remainder of netlib buffer in backtrack buffer */
PRUint32 new_backtrack_buflen = src->pub.bytes_in_buffer + src->decoder->mBackBufferLen;
/* Make sure backtrack buffer is big enough to hold new data. */
if (src->decoder->mBackBufferSize < new_backtrack_buflen) {
/* Round up to multiple of 16 bytes. */
PRUint32 roundup_buflen = ((new_backtrack_buflen + 15) >> 4) << 4;
if (src->decoder->mBackBufferSize) {
src->decoder->mBackBuffer =
(JOCTET *)PR_REALLOC(src->decoder->mBackBuffer, roundup_buflen);
} else {
src->decoder->mBackBuffer = (JOCTET*)PR_MALLOC(roundup_buflen);
}
/* Check for OOM */
if (!src->decoder->mBackBuffer) {
#if 0
j_common_ptr cinfo = (j_common_ptr)(&src->js->jd);
cinfo->err->msg_code = JERR_OUT_OF_MEMORY;
my_error_exit(cinfo);
#endif
}
src->decoder->mBackBufferSize = (size_t)roundup_buflen;
/* Check for malformed MARKER segment lengths. */
if (new_backtrack_buflen > MAX_JPEG_MARKER_LENGTH) {
my_error_exit((j_common_ptr)(&src->decoder->mInfo));
}
}
/* Copy remainder of netlib buffer into backtrack buffer. */
nsCRT::memmove(src->decoder->mBackBuffer + src->decoder->mBackBufferLen,
src->pub.next_input_byte,
src->pub.bytes_in_buffer);
/* Point to start of data to be rescanned. */
src->pub.next_input_byte = src->decoder->mBackBuffer + src->decoder->mBackBufferLen - src->decoder->mBackBufferUnreadLen;
src->pub.bytes_in_buffer += src->decoder->mBackBufferUnreadLen;
src->decoder->mBackBufferLen = (size_t)new_backtrack_buflen;
src->decoder->mFillState = READING_BACK;
return PR_FALSE;
}
break;
}
return PR_FALSE;
}
/******************************************************************************/
/* data source manager method */
/*
* Terminate source --- called by jpeg_finish_decompress() after all
* data has been read to clean up JPEG source manager. NOT called by
* jpeg_abort() or jpeg_destroy().
*/
void PR_CALLBACK
term_source (j_decompress_ptr jd)
{
decoder_source_mgr *src = (decoder_source_mgr *)jd->src;
if (src->decoder->mObserver) {
src->decoder->mObserver->OnStopFrame(nsnull, nsnull, src->decoder->mFrame);
src->decoder->mObserver->OnStopContainer(nsnull, nsnull, src->decoder->mImage);
src->decoder->mObserver->OnStopDecode(nsnull, nsnull, NS_OK, nsnull);
}
/* No work necessary here */
}

View File

@@ -0,0 +1,121 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
*
* The contents of this file are subject to the Mozilla Public
* License Version 1.1 (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/MPL/
*
* 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.org code.
*
* The Initial Developer of the Original Code is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 2001 Netscape Communications Corporation.
* All Rights Reserved.
*
* Contributor(s):
* Stuart Parmenter <pavlov@netscape.com>
*/
#ifndef nsJPEGDecoder_h__
#define nsJPEGDecoder_h__
#include "imgIDecoder.h"
#include "nsCOMPtr.h"
#include "imgIContainer.h"
#include "gfxIImageFrame.h"
#include "imgIDecoderObserver.h"
#include "imgIRequest.h"
#include "nsIInputStream.h"
#include "nsIPipe.h"
extern "C" {
#include "jpeglib.h"
}
#include <setjmp.h>
#define NS_JPEGDECODER_CID \
{ /* 5871a422-1dd2-11b2-ab3f-e2e56be5da9c */ \
0x5871a422, \
0x1dd2, \
0x11b2, \
{0xab, 0x3f, 0xe2, 0xe5, 0x6b, 0xe5, 0xda, 0x9c} \
}
typedef struct {
struct jpeg_error_mgr pub; /* "public" fields for IJG library*/
jmp_buf setjmp_buffer; /* For handling catastropic errors */
} decoder_error_mgr;
typedef enum {
JPEG_HEADER, /* Reading JFIF headers */
JPEG_START_DECOMPRESS,
JPEG_DECOMPRESS_PROGRESSIVE, /* Output progressive pixels */
JPEG_DECOMPRESS_SEQUENTIAL, /* Output sequential pixels */
JPEG_FINAL_PROGRESSIVE_SCAN_OUTPUT,
JPEG_DONE,
JPEG_SINK_NON_JPEG_TRAILER, /* Some image files have a */
/* non-JPEG trailer */
JPEG_ERROR
} jstate;
class nsJPEGDecoder : public imgIDecoder
{
public:
NS_DECL_ISUPPORTS
NS_DECL_IMGIDECODER
NS_DECL_NSIOUTPUTSTREAM
nsJPEGDecoder();
virtual ~nsJPEGDecoder();
PRBool FillInput(j_decompress_ptr jd);
PRUint32 mBytesToSkip;
protected:
int OutputScanlines(int num_scanlines);
public:
nsCOMPtr<imgIContainer> mImage;
nsCOMPtr<gfxIImageFrame> mFrame;
nsCOMPtr<imgIRequest> mRequest;
nsCOMPtr<imgIDecoderObserver> mObserver;
struct jpeg_decompress_struct mInfo;
decoder_error_mgr mErr;
jstate mState;
JSAMPARRAY mSamples;
JSAMPARRAY mSamples3;
PRUint8* mRGBPadRow;
PRUint32 mRGBPadRowLength;
PRInt32 mCompletedPasses;
PRInt32 mPasses;
int mFillState;
JOCTET *mBuffer;
PRUint32 mBufferLen; // amount of data currently in mBuffer
PRUint32 mBufferSize; // size in bytes what mBuffer was created with
JOCTET *mBackBuffer;
PRUint32 mBackBufferLen; // Offset of end of active backtrack data
PRUint32 mBackBufferSize; // size in bytes what mBackBuffer was created with
PRUint32 mBackBufferUnreadLen; // amount of data currently in mBackBuffer
};
#endif // nsJPEGDecoder_h__

View File

@@ -0,0 +1,42 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
*
* The contents of this file are subject to the Mozilla Public
* License Version 1.1 (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/MPL/
*
* 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.org code.
*
* The Initial Developer of the Original Code is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 2001 Netscape Communications Corporation. All
* Rights Reserved.
*
* Contributor(s):
* Stuart Parmenter <pavlov@netscape.com>
*/
#include "nsIGenericFactory.h"
#include "nsIModule.h"
#include "nsJPEGDecoder.h"
// objects that just require generic constructors
NS_GENERIC_FACTORY_CONSTRUCTOR(nsJPEGDecoder)
static nsModuleComponentInfo components[] =
{
{ "ppm decoder",
NS_JPEGDECODER_CID,
"@mozilla.org/image/decoder;2?type=image/jpeg",
nsJPEGDecoderConstructor, },
};
NS_IMPL_NSGETMODULE("nsJPEGDecoderModule", components)

View File

@@ -0,0 +1,16 @@
?Release@nsJPEGDecoder@@UAGKXZ ; 172
?AddRef@nsJPEGDecoder@@UAGKXZ ; 172
?fill_input_buffer@@YAEPAUjpeg_decompress_struct@@@Z ; 126
?skip_input_data@@YAXPAUjpeg_decompress_struct@@J@Z ; 109
?WriteFrom@nsJPEGDecoder@@UAGIPAVnsIInputStream@@IPAI@Z ; 106
?OutputScanlines@nsJPEGDecoder@@IAEHH@Z ; 93
?init_source@@YAXPAUjpeg_decompress_struct@@@Z ; 86
??1nsJPEGDecoder@@UAE@XZ ; 86
?Close@nsJPEGDecoder@@UAGIXZ ; 86
?term_source@@YAXPAUjpeg_decompress_struct@@@Z ; 86
?Init@nsJPEGDecoder@@UAGIPAVimgIRequest@@@Z ; 86
??0nsJPEGDecoder@@QAE@XZ ; 86
?Flush@nsJPEGDecoder@@UAGIXZ ; 86
?QueryInterface@nsJPEGDecoder@@UAGIABUnsID@@PAPAX@Z ; 86
??_EnsJPEGDecoder@@UAEPAXI@Z ; 86
_NSGetModule ; 1

View File

@@ -0,0 +1,26 @@
#
# The contents of this file are subject to the Mozilla Public
# License Version 1.1 (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/MPL/
#
# 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.org code
#
# The Initial Developer of the Original Code is Netscape
# Communications Corporation. Portions created by Netscape are
# Copyright (C) 2001 Netscape Communications Corporation. All
# Rights Reserved.
#
# Contributor(s):
#
DEPTH=..\..\..
DIRS = ppm gif png jpeg
!include $(DEPTH)\config\rules.mak

View File

@@ -0,0 +1,42 @@
#
# The contents of this file are subject to the Mozilla Public
# License Version 1.1 (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/MPL/
#
# 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.org code
#
# The Initial Developer of the Original Code is Netscape
# Communications Corporation. Portions created by Netscape are
# Copyright (C) 2001 Netscape Communications Corporation. All
# Rights Reserved.
#
# Contributor(s):
#
DEPTH = ../../../..
topsrcdir = @top_srcdir@
srcdir = @srcdir@
VPATH = @srcdir@
include $(DEPTH)/config/autoconf.mk
MODULE = imgpng
LIBRARY_NAME = imgpng
IS_COMPONENT = 1
REQUIRES = xpcom necko layout png gfx2 imglib2
CPPSRCS = nsPNGDecoder.cpp nsPNGFactory.cpp
EXTRA_DSO_LDOPTS = $(PNG_LIBS) $(ZLIB_LIBS) \
$(MOZ_COMPONENT_LIBS) \
$(NULL)
include $(topsrcdir)/config/rules.mk

View File

@@ -0,0 +1,53 @@
#!nmake
#
# The contents of this file are subject to the Mozilla Public
# License Version 1.1 (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/MPL/
#
# 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.org code
#
# The Initial Developer of the Original Code is Netscape
# Communications Corporation. Portions created by Netscape are
# Copyright (C) 2001 Netscape Communications Corporation. All
# Rights Reserved.
#
# Contributor(s):
# Stuart Parmenter <pavlov@netscape.com>
#
DEPTH=..\..\..\..
include <$(DEPTH)/config/config.mak>
MODULE = imgpng
LIBRARY_NAME = imgpng
DLL = $(OBJDIR)\$(LIBRARY_NAME).dll
MAKE_OBJ_TYPE = DLL
OBJS = \
.\$(OBJDIR)\nsPNGDecoder.obj \
.\$(OBJDIR)\nsPNGFactory.obj \
$(NULL)
LLIBS=\
$(LIBNSPR) \
$(DIST)\lib\xpcom.lib \
$(DIST)\lib\png.lib \
$(DIST)\lib\zlib.lib \
$(DIST)\lib\gkgfxwin.lib \
$(NULL)
include <$(DEPTH)\config\rules.mak>
install:: $(DLL)
$(MAKE_INSTALL) .\$(OBJDIR)\$(LIBRARY_NAME).dll $(DIST)\bin\components
$(MAKE_INSTALL) .\$(OBJDIR)\$(LIBRARY_NAME).lib $(DIST)\lib
clobber::
rm -f $(DIST)\bin\components\$(LIBRARY_NAME).dll
rm -f $(DIST)\lib\$(LIBRARY_NAME).lib

View File

@@ -0,0 +1,553 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
*
* The contents of this file are subject to the Mozilla Public
* License Version 1.1 (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/MPL/
*
* 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.org code.
*
* The Initial Developer of the Original Code is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 2001 Netscape Communications Corporation.
* All Rights Reserved.
*
* Contributor(s):
* Stuart Parmenter <pavlov@netscape.com>
*
*/
#include "nsPNGDecoder.h"
#include "nsIInputStream.h"
#include "nspr.h"
#include "nsIComponentManager.h"
#include "png.h"
#include "nsIStreamObserver.h"
#include "nsRect.h"
#include "nsMemory.h"
#include "imgIContainerObserver.h"
// XXX we need to be sure to fire onStopDecode messages to mObserver in error cases.
NS_IMPL_ISUPPORTS2(nsPNGDecoder, imgIDecoder, nsIOutputStream)
nsPNGDecoder::nsPNGDecoder()
{
NS_INIT_ISUPPORTS();
mPNG = nsnull;
mInfo = nsnull;
colorLine = 0;
alphaLine = 0;
interlacebuf = 0;
}
nsPNGDecoder::~nsPNGDecoder()
{
if (colorLine)
nsMemory::Free(colorLine);
if (alphaLine)
nsMemory::Free(alphaLine);
if (interlacebuf)
nsMemory::Free(interlacebuf);
}
/** imgIDecoder methods **/
/* void init (in imgIRequest aRequest); */
NS_IMETHODIMP nsPNGDecoder::Init(imgIRequest *aRequest)
{
mRequest = aRequest;
mObserver = do_QueryInterface(aRequest); // we're holding 2 strong refs to the request.
aRequest->GetImage(getter_AddRefs(mImage));
/* do png init stuff */
/* Initialize the container's source image header. */
/* Always decode to 24 bit pixdepth */
mPNG = png_create_read_struct(PNG_LIBPNG_VER_STRING,
NULL, NULL,
NULL);
if (!mPNG) {
return NS_ERROR_FAILURE;
}
mInfo = png_create_info_struct(mPNG);
if (!mInfo) {
png_destroy_read_struct(&mPNG, NULL, NULL);
return NS_ERROR_FAILURE;
}
/* use ic as libpng "progressive pointer" (retrieve in callbacks) */
png_set_progressive_read_fn(mPNG, NS_STATIC_CAST(png_voidp, this), nsPNGDecoder::info_callback, nsPNGDecoder::row_callback, nsPNGDecoder::end_callback);
return NS_OK;
}
/* readonly attribute imgIRequest request; */
NS_IMETHODIMP nsPNGDecoder::GetRequest(imgIRequest * *aRequest)
{
*aRequest = mRequest;
NS_ADDREF(*aRequest);
return NS_OK;
}
/** nsIOutputStream methods **/
/* void close (); */
NS_IMETHODIMP nsPNGDecoder::Close()
{
if (mPNG)
png_destroy_read_struct(&mPNG, mInfo ? &mInfo : NULL, NULL);
return NS_OK;
}
/* void flush (); */
NS_IMETHODIMP nsPNGDecoder::Flush()
{
return NS_ERROR_NOT_IMPLEMENTED;
}
/* unsigned long write (in string buf, in unsigned long count); */
NS_IMETHODIMP nsPNGDecoder::Write(const char *buf, PRUint32 count, PRUint32 *_retval)
{
return NS_ERROR_NOT_IMPLEMENTED;
}
static NS_METHOD ReadDataOut(nsIInputStream* in,
void* closure,
const char* fromRawSegment,
PRUint32 toOffset,
PRUint32 count,
PRUint32 *writeCount)
{
nsPNGDecoder *decoder = NS_STATIC_CAST(nsPNGDecoder*, closure);
// we need to do the setjmp here otherwise bad things will happen
if (setjmp(decoder->mPNG->jmpbuf)) {
png_destroy_read_struct(&decoder->mPNG, &decoder->mInfo, NULL);
// is this NS_ERROR_FAILURE enough?
decoder->mRequest->Cancel(NS_BINDING_ABORTED); // XXX is this the correct error ?
return NS_ERROR_FAILURE;
}
*writeCount = decoder->ProcessData((unsigned char*)fromRawSegment, count);
return NS_OK;
}
PRUint32 nsPNGDecoder::ProcessData(unsigned char *data, PRUint32 count)
{
png_process_data(mPNG, mInfo, data, count);
return count; // we always consume all the data
}
/* unsigned long writeFrom (in nsIInputStream inStr, in unsigned long count); */
NS_IMETHODIMP nsPNGDecoder::WriteFrom(nsIInputStream *inStr, PRUint32 count, PRUint32 *_retval)
{
// PRUint32 sourceOffset = *_retval;
inStr->ReadSegments(ReadDataOut, this, count, _retval);
return NS_OK;
}
/* [noscript] unsigned long writeSegments (in nsReadSegmentFun reader, in voidPtr closure, in unsigned long count); */
NS_IMETHODIMP nsPNGDecoder::WriteSegments(nsReadSegmentFun reader, void * closure, PRUint32 count, PRUint32 *_retval)
{
return NS_ERROR_NOT_IMPLEMENTED;
}
/* attribute boolean nonBlocking; */
NS_IMETHODIMP nsPNGDecoder::GetNonBlocking(PRBool *aNonBlocking)
{
return NS_ERROR_NOT_IMPLEMENTED;
}
NS_IMETHODIMP nsPNGDecoder::SetNonBlocking(PRBool aNonBlocking)
{
return NS_ERROR_NOT_IMPLEMENTED;
}
/* attribute nsIOutputStreamObserver observer; */
NS_IMETHODIMP nsPNGDecoder::GetObserver(nsIOutputStreamObserver * *aObserver)
{
return NS_ERROR_NOT_IMPLEMENTED;
}
NS_IMETHODIMP nsPNGDecoder::SetObserver(nsIOutputStreamObserver * aObserver)
{
return NS_ERROR_NOT_IMPLEMENTED;
}
void
nsPNGDecoder::info_callback(png_structp png_ptr, png_infop info_ptr)
{
/* int number_passes; NOT USED */
png_uint_32 width, height;
int bit_depth, color_type, interlace_type, compression_type, filter_type;
int channels;
double LUT_exponent, CRT_exponent = 2.2, display_exponent, aGamma;
png_bytep trans=NULL;
int num_trans =0;
/* always decode to 24-bit RGB or 32-bit RGBA */
png_get_IHDR(png_ptr, info_ptr, &width, &height, &bit_depth, &color_type,
&interlace_type, &compression_type, &filter_type);
if (color_type == PNG_COLOR_TYPE_PALETTE)
png_set_expand(png_ptr);
if (color_type == PNG_COLOR_TYPE_GRAY && bit_depth < 8)
png_set_expand(png_ptr);
if (png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS)) {
png_get_tRNS(png_ptr, info_ptr, &trans, &num_trans, NULL);
png_set_expand(png_ptr);
}
if (bit_depth == 16)
png_set_strip_16(png_ptr);
if (color_type == PNG_COLOR_TYPE_GRAY ||
color_type == PNG_COLOR_TYPE_GRAY_ALPHA)
png_set_gray_to_rgb(png_ptr);
#ifdef XP_PC
// windows likes BGR
png_set_bgr(png_ptr);
#endif
/* set up gamma correction for Mac, Unix and (Win32 and everything else)
* using educated guesses for display-system exponents; do preferences
* later */
#if defined(XP_MAC)
LUT_exponent = 1.8 / 2.61;
#elif defined(XP_UNIX)
# if defined(__sgi)
LUT_exponent = 1.0 / 1.7; /* typical default for SGI console */
# elif defined(NeXT)
LUT_exponent = 1.0 / 2.2; /* typical default for NeXT cube */
# else
LUT_exponent = 1.0; /* default for most other Unix workstations */
# endif
#else
LUT_exponent = 1.0; /* virtually all PCs and most other systems */
#endif
/* (alternatively, could check for SCREEN_GAMMA environment variable) */
display_exponent = LUT_exponent * CRT_exponent;
if (png_get_gAMA(png_ptr, info_ptr, &aGamma))
png_set_gamma(png_ptr, display_exponent, aGamma);
else
png_set_gamma(png_ptr, display_exponent, 0.45455);
/* let libpng expand interlaced images */
if (interlace_type == PNG_INTERLACE_ADAM7) {
/* number_passes = */
png_set_interlace_handling(png_ptr);
}
/* now all of those things we set above are used to update various struct
* members and whatnot, after which we can get channels, rowbytes, etc. */
png_read_update_info(png_ptr, info_ptr);
channels = png_get_channels(png_ptr, info_ptr);
PR_ASSERT(channels == 3 || channels == 4);
/*---------------------------------------------------------------*/
/* copy PNG info into imagelib structs (formerly png_set_dims()) */
/*---------------------------------------------------------------*/
PRInt32 alpha_bits = 1;
if (channels > 3) {
/* check if alpha is coming from a tRNS chunk and is binary */
if (num_trans) {
/* if it's not a indexed color image, tRNS means binary */
if (color_type == PNG_COLOR_TYPE_PALETTE) {
for (int i=0; i<num_trans; i++) {
if ((trans[i] != 0) && (trans[i] != 255)) {
alpha_bits = 8;
break;
}
}
}
} else {
alpha_bits = 8;
}
}
nsPNGDecoder *decoder = NS_STATIC_CAST(nsPNGDecoder*, png_get_progressive_ptr(png_ptr));
if (decoder->mObserver)
decoder->mObserver->OnStartDecode(nsnull, nsnull);
// since the png is only 1 frame, initalize the container to the width and height of the frame
decoder->mImage->Init(width, height, decoder->mObserver);
if (decoder->mObserver)
decoder->mObserver->OnStartContainer(nsnull, nsnull, decoder->mImage);
decoder->mFrame = do_CreateInstance("@mozilla.org/gfx/image/frame;2");
#if 0
// XXX should we longjmp to png_ptr->jumpbuf here if we failed?
if (!decoder->mFrame)
return NS_ERROR_FAILURE;
#endif
gfx_format format;
if (channels == 3) {
format = gfxIFormats::RGB;
} else if (channels > 3) {
if (alpha_bits == 8) {
decoder->mImage->GetPreferredAlphaChannelFormat(&format);
} else if (alpha_bits == 1) {
format = gfxIFormats::RGB_A1;
}
}
#ifdef XP_PC
// XXX this works...
format += 1; // RGB to BGR
#endif
// then initalize the frame and append it to the container
decoder->mFrame->Init(0, 0, width, height, format);
decoder->mImage->AppendFrame(decoder->mFrame);
if (decoder->mObserver)
decoder->mObserver->OnStartFrame(nsnull, nsnull, decoder->mFrame);
PRUint32 bpr, abpr;
decoder->mFrame->GetImageBytesPerRow(&bpr);
decoder->mFrame->GetAlphaBytesPerRow(&abpr);
decoder->colorLine = (PRUint8 *)nsMemory::Alloc(bpr);
if (channels > 3)
decoder->alphaLine = (PRUint8 *)nsMemory::Alloc(abpr);
if (interlace_type == PNG_INTERLACE_ADAM7) {
decoder->interlacebuf = (PRUint8 *)nsMemory::Alloc(channels*width*height);
decoder->ibpr = channels*width;
if (!decoder->interlacebuf) {
// return NS_ERROR_FAILURE;
}
}
return;
}
void
nsPNGDecoder::row_callback(png_structp png_ptr, png_bytep new_row,
png_uint_32 row_num, int pass)
{
/* libpng comments:
*
* this function is called for every row in the image. If the
* image is interlacing, and you turned on the interlace handler,
* this function will be called for every row in every pass.
* Some of these rows will not be changed from the previous pass.
* When the row is not changed, the new_row variable will be NULL.
* The rows and passes are called in order, so you don't really
* need the row_num and pass, but I'm supplying them because it
* may make your life easier.
*
* For the non-NULL rows of interlaced images, you must call
* png_progressive_combine_row() passing in the row and the
* old row. You can call this function for NULL rows (it will
* just return) and for non-interlaced images (it just does the
* memcpy for you) if it will make the code easier. Thus, you
* can just do this for all cases:
*
* png_progressive_combine_row(png_ptr, old_row, new_row);
*
* where old_row is what was displayed for previous rows. Note
* that the first pass (pass == 0 really) will completely cover
* the old row, so the rows do not have to be initialized. After
* the first pass (and only for interlaced images), you will have
* to pass the current row, and the function will combine the
* old row and the new row.
*/
nsPNGDecoder *decoder = NS_STATIC_CAST(nsPNGDecoder*, png_get_progressive_ptr(png_ptr));
PRUint32 bpr, abpr;
decoder->mFrame->GetImageBytesPerRow(&bpr);
decoder->mFrame->GetAlphaBytesPerRow(&abpr);
png_bytep line;
if (decoder->interlacebuf) {
line = decoder->interlacebuf+(row_num*decoder->ibpr);
png_progressive_combine_row(png_ptr, line, new_row);
}
else
line = new_row;
if (new_row) {
nscoord width;
decoder->mFrame->GetWidth(&width);
PRUint32 iwidth = width;
gfx_format format;
decoder->mFrame->GetFormat(&format);
PRUint8 *aptr, *cptr;
// The mac specific ifdefs in the code below are there to make sure we
// always fill in 4 byte pixels right now, which is what the mac always
// allocates for its pixel buffers in true color mode. This will change
// when we start storing images with color palettes when they don't need
// true color support (GIFs).
switch (format) {
case gfxIFormats::RGB:
case gfxIFormats::BGR:
#ifdef XP_MAC
cptr = decoder->colorLine;
for (PRUint32 x=0; x<iwidth; x++) {
*cptr++ = 0;
*cptr++ = *line++;
*cptr++ = *line++;
*cptr++ = *line++;
}
decoder->mFrame->SetImageData(decoder->colorLine, bpr, row_num*bpr);
#else
decoder->mFrame->SetImageData((PRUint8*)line, bpr, row_num*bpr);
#endif
break;
case gfxIFormats::RGB_A1:
case gfxIFormats::BGR_A1:
{
cptr = decoder->colorLine;
aptr = decoder->alphaLine;
memset(aptr, 0, abpr);
for (PRUint32 x=0; x<iwidth; x++) {
#ifdef XP_MAC
*cptr++ = 0;
#endif
*cptr++ = *line++;
*cptr++ = *line++;
*cptr++ = *line++;
if (*line++) {
aptr[x>>3] |= 1<<(7-x&0x7);
}
}
decoder->mFrame->SetImageData(decoder->colorLine, bpr, row_num*bpr);
decoder->mFrame->SetAlphaData(decoder->alphaLine, abpr, row_num*abpr);
}
break;
case gfxIFormats::RGB_A8:
case gfxIFormats::BGR_A8:
{
cptr = decoder->colorLine;
aptr = decoder->alphaLine;
for (PRUint32 x=0; x<iwidth; x++) {
#ifdef XP_MAC
*cptr++ = 0;
#endif
*cptr++ = *line++;
*cptr++ = *line++;
*cptr++ = *line++;
*aptr++ = *line++;
}
decoder->mFrame->SetImageData(decoder->colorLine, bpr, row_num*bpr);
decoder->mFrame->SetAlphaData(decoder->alphaLine, abpr, row_num*abpr);
}
break;
case gfxIFormats::RGBA:
case gfxIFormats::BGRA:
#ifdef XP_MAC
{
cptr = decoder->colorLine;
aptr = decoder->alphaLine;
for (PRUint32 x=0; x<iwidth; x++) {
*cptr++ = 0;
*cptr++ = *line++;
*cptr++ = *line++;
*cptr++ = *line++;
*aptr++ = *line++;
}
decoder->mFrame->SetImageData(decoder->colorLine, bpr, row_num*bpr);
decoder->mFrame->SetAlphaData(decoder->alphaLine, abpr, row_num*abpr);
}
#else
decoder->mFrame->SetImageData(line, bpr, row_num*bpr);
#endif
break;
}
nsRect r(0, row_num, width, 1);
decoder->mObserver->OnDataAvailable(nsnull, nsnull, decoder->mFrame, &r);
}
}
void
nsPNGDecoder::end_callback(png_structp png_ptr, png_infop info_ptr)
{
/* libpng comments:
*
* this function is called when the whole image has been read,
* including any chunks after the image (up to and including
* the IEND). You will usually have the same info chunk as you
* had in the header, although some data may have been added
* to the comments and time fields.
*
* Most people won't do much here, perhaps setting a flag that
* marks the image as finished.
*/
nsPNGDecoder *decoder = NS_STATIC_CAST(nsPNGDecoder*, png_get_progressive_ptr(png_ptr));
if (decoder->mObserver) {
decoder->mObserver->OnStopFrame(nsnull, nsnull, decoder->mFrame);
decoder->mObserver->OnStopContainer(nsnull, nsnull, decoder->mImage);
decoder->mObserver->OnStopDecode(nsnull, nsnull, NS_OK, nsnull);
}
}

View File

@@ -0,0 +1,82 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
*
* The contents of this file are subject to the Mozilla Public
* License Version 1.1 (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/MPL/
*
* 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.org code.
*
* The Initial Developer of the Original Code is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 2001 Netscape Communications Corporation.
* All Rights Reserved.
*
* Contributor(s):
* Stuart Parmenter <pavlov@netscape.com>
*/
#ifndef nsPNGDecoder_h__
#define nsPNGDecoder_h__
#include "imgIDecoder.h"
#include "imgIContainer.h"
#include "imgIDecoderObserver.h"
#include "gfxIImageFrame.h"
#include "imgIRequest.h"
#include "nsCOMPtr.h"
#include "png.h"
#define NS_PNGDECODER_CID \
{ /* 36fa00c2-1dd2-11b2-be07-d16eeb4c50ed */ \
0x36fa00c2, \
0x1dd2, \
0x11b2, \
{0xbe, 0x07, 0xd1, 0x6e, 0xeb, 0x4c, 0x50, 0xed} \
}
class nsPNGDecoder : public imgIDecoder
{
public:
NS_DECL_ISUPPORTS
NS_DECL_IMGIDECODER
NS_DECL_NSIOUTPUTSTREAM
nsPNGDecoder();
virtual ~nsPNGDecoder();
PR_STATIC_CALLBACK(void)
info_callback(png_structp png_ptr, png_infop info_ptr);
PR_STATIC_CALLBACK(void)
row_callback(png_structp png_ptr, png_bytep new_row,
png_uint_32 row_num, int pass);
PR_STATIC_CALLBACK(void)
end_callback(png_structp png_ptr, png_infop info_ptr);
inline PRUint32 ProcessData(unsigned char *data, PRUint32 count);
public:
nsCOMPtr<imgIContainer> mImage;
nsCOMPtr<gfxIImageFrame> mFrame;
nsCOMPtr<imgIRequest> mRequest;
nsCOMPtr<imgIDecoderObserver> mObserver; // this is just qi'd from mRequest for speed
png_structp mPNG;
png_infop mInfo;
PRUint8 *colorLine, *alphaLine;
PRUint8 *interlacebuf;
PRUint32 ibpr;
};
#endif // nsPNGDecoder_h__

View File

@@ -0,0 +1,46 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
*
* The contents of this file are subject to the Mozilla Public
* License Version 1.1 (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/MPL/
*
* 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.org code.
*
* The Initial Developer of the Original Code is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 2001 Netscape Communications Corporation. All
* Rights Reserved.
*
* Contributor(s):
* Stuart Parmenter <pavlov@netscape.com>
*/
#include "nsIGenericFactory.h"
#include "nsIModule.h"
#include "nsPNGDecoder.h"
// objects that just require generic constructors
NS_GENERIC_FACTORY_CONSTRUCTOR(nsPNGDecoder)
static nsModuleComponentInfo components[] =
{
{ "PNG decoder",
NS_PNGDECODER_CID,
"@mozilla.org/image/decoder;2?type=image/png",
nsPNGDecoderConstructor, },
{ "PNG decoder",
NS_PNGDECODER_CID,
"@mozilla.org/image/decoder;2?type=image/x-png",
nsPNGDecoderConstructor, },
};
NS_IMPL_NSGETMODULE("nsPNGDecoderModule", components)

View File

@@ -0,0 +1,42 @@
#
# The contents of this file are subject to the Mozilla Public
# License Version 1.1 (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/MPL/
#
# 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.org code
#
# The Initial Developer of the Original Code is Netscape
# Communications Corporation. Portions created by Netscape are
# Copyright (C) 2001 Netscape Communications Corporation. All
# Rights Reserved.
#
# Contributor(s):
#
DEPTH = ../../../..
topsrcdir = @top_srcdir@
srcdir = @srcdir@
VPATH = @srcdir@
include $(DEPTH)/config/autoconf.mk
MODULE = imgppm
LIBRARY_NAME = imgppm
IS_COMPONENT = 1
REQUIRES = xpcom layout necko gfx2 imglib2
CPPSRCS = nsPPMDecoder.cpp nsPPMFactory.cpp
EXTRA_DSO_LDOPTS = \
$(MOZ_COMPONENT_LIBS) \
$(NULL)
include $(topsrcdir)/config/rules.mk

View File

@@ -0,0 +1,51 @@
#!nmake
#
# The contents of this file are subject to the Mozilla Public
# License Version 1.1 (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/MPL/
#
# 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.org code
#
# The Initial Developer of the Original Code is Netscape
# Communications Corporation. Portions created by Netscape are
# Copyright (C) 2001 Netscape Communications Corporation. All
# Rights Reserved.
#
# Contributor(s):
# Stuart Parmenter <pavlov@netscape.com>
#
DEPTH=..\..\..\..
include <$(DEPTH)/config/config.mak>
MODULE = imgppm
LIBRARY_NAME = imgppm
DLL = $(OBJDIR)\$(LIBRARY_NAME).dll
MAKE_OBJ_TYPE = DLL
OBJS = \
.\$(OBJDIR)\nsPPMDecoder.obj \
.\$(OBJDIR)\nsPPMFactory.obj \
$(NULL)
LLIBS=\
$(LIBNSPR) \
$(DIST)\lib\xpcom.lib \
$(DIST)\lib\gkgfxwin.lib \
$(NULL)
include <$(DEPTH)\config\rules.mak>
install:: $(DLL)
$(MAKE_INSTALL) .\$(OBJDIR)\$(LIBRARY_NAME).dll $(DIST)\bin\components
$(MAKE_INSTALL) .\$(OBJDIR)\$(LIBRARY_NAME).lib $(DIST)\lib
clobber::
rm -f $(DIST)\bin\components\$(LIBRARY_NAME).dll
rm -f $(DIST)\lib\$(LIBRARY_NAME).lib

View File

@@ -0,0 +1,305 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
*
* The contents of this file are subject to the Mozilla Public
* License Version 1.1 (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/MPL/
*
* 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.org code.
*
* The Initial Developer of the Original Code is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 2001 Netscape Communications Corporation.
* All Rights Reserved.
*
* Contributor(s):
* Stuart Parmenter <pavlov@netscape.com>
*
*/
#include "nsPPMDecoder.h"
#include "nsIInputStream.h"
#include "imgIContainer.h"
#include "imgIContainerObserver.h"
#include "nspr.h"
#include "nsIComponentManager.h"
#include "nsRect.h"
NS_IMPL_ISUPPORTS2(nsPPMDecoder, imgIDecoder, nsIOutputStream)
nsPPMDecoder::nsPPMDecoder()
{
NS_INIT_ISUPPORTS();
mDataReceived = 0;
mDataWritten = 0;
mDataLeft = 0;
mPrevData = nsnull;
}
nsPPMDecoder::~nsPPMDecoder()
{
}
/** imgIDecoder methods **/
/* void init (in imgIRequest aRequest); */
NS_IMETHODIMP nsPPMDecoder::Init(imgIRequest *aRequest)
{
mRequest = aRequest;
mObserver = do_QueryInterface(aRequest); // we're holding 2 strong refs to the request.
aRequest->GetImage(getter_AddRefs(mImage));
mFrame = do_CreateInstance("@mozilla.org/gfx/image/frame;2");
if (!mFrame)
return NS_ERROR_FAILURE;
return NS_OK;
}
/* readonly attribute imgIRequest request; */
NS_IMETHODIMP nsPPMDecoder::GetRequest(imgIRequest * *aRequest)
{
*aRequest = mRequest;
NS_ADDREF(*aRequest);
return NS_OK;
}
/** nsIOutputStream methods **/
/* void close (); */
NS_IMETHODIMP nsPPMDecoder::Close()
{
if (mObserver) {
mObserver->OnStopFrame(nsnull, nsnull, mFrame);
mObserver->OnStopContainer(nsnull, nsnull, mImage);
mObserver->OnStopDecode(nsnull, nsnull, NS_OK, nsnull);
}
return NS_OK;
}
/* void flush (); */
NS_IMETHODIMP nsPPMDecoder::Flush()
{
return NS_ERROR_NOT_IMPLEMENTED;
}
/* unsigned long write (in string buf, in unsigned long count); */
NS_IMETHODIMP nsPPMDecoder::Write(const char *buf, PRUint32 count, PRUint32 *_retval)
{
return NS_ERROR_NOT_IMPLEMENTED;
}
static char *__itoa(int n)
{
char *s;
int i, j, sign, tmp;
/* check sign and convert to positive to stringify numbers */
if ( (sign = n) < 0)
n = -n;
i = 0;
s = (char*) malloc(sizeof(char));
/* grow string as needed to add numbers from powers of 10
* down till none left
*/
do
{
s = (char*) realloc(s, (i+1)*sizeof(char));
s[i++] = n % 10 + '0'; /* '0' or 30 is where ASCII numbers start */
s[i] = '\0';
}
while( (n /= 10) > 0);
/* tack on minus sign if we found earlier that this was negative */
if (sign < 0)
{
s = (char*) realloc(s, (i+1)*sizeof(char));
s[i++] = '-';
}
s[i] = '\0';
/* pop numbers (and sign) off of string to push back into right direction */
for (i = 0, j = strlen(s) - 1; i < j; i++, j--)
{
tmp = s[i];
s[i] = s[j];
s[j] = tmp;
}
return s;
}
/* unsigned long writeFrom (in nsIInputStream inStr, in unsigned long count); */
NS_IMETHODIMP nsPPMDecoder::WriteFrom(nsIInputStream *inStr, PRUint32 count, PRUint32 *_retval)
{
nsresult rv;
char *buf = (char *)PR_Malloc(count + mDataLeft);
if (!buf)
return NS_ERROR_OUT_OF_MEMORY; /* we couldn't allocate the object */
// read the data from the input stram...
PRUint32 readLen;
rv = inStr->Read(buf+mDataLeft, count, &readLen);
PRUint32 dataLen = readLen + mDataLeft;
if (mPrevData) {
strncpy(buf, mPrevData, mDataLeft);
PR_Free(mPrevData);
mPrevData = nsnull;
mDataLeft = 0;
}
char *data = buf;
if (NS_FAILED(rv)) return rv;
if (mDataReceived == 0) {
mObserver->OnStartDecode(nsnull, nsnull);
// Check the magic number
char type;
if ((sscanf(data, "P%c\n", &type) !=1) || (type != '6')) {
return NS_ERROR_FAILURE;
}
int i = 3;
data += i;
#if 0
// XXX
// Ignore comments
while ((input = fgetc(f)) == '#')
fgets(junk, 512, f);
ungetc(input, f);
#endif
// Read size
int w, h, mcv;
if (sscanf(data, "%d %d\n%d\n", &w, &h, &mcv) != 3) {
return NS_ERROR_FAILURE;
}
char *ws = __itoa(w), *hs = __itoa(h), *mcvs = __itoa(mcv);
int j = strlen(ws) + strlen(hs) + strlen(mcvs) + 3;
data += j;
// free(ws);
// free(hs);
// free(mcvs);
readLen -= i + j;
dataLen = readLen; // since this is the first pass, we don't have any data waiting that we need to keep track of
mImage->Init(w, h, mObserver);
if (mObserver)
mObserver->OnStartContainer(nsnull, nsnull, mImage);
mFrame->Init(0, 0, w, h, gfxIFormats::RGB);
mImage->AppendFrame(mFrame);
if (mObserver)
mObserver->OnStartFrame(nsnull, nsnull, mFrame);
}
PRUint32 bpr;
nscoord width;
mFrame->GetImageBytesPerRow(&bpr);
mFrame->GetWidth(&width);
// XXX ceil?
PRUint32 real_bpr = width * 3;
PRUint32 i = 0;
PRUint32 rownum = mDataWritten / real_bpr; // XXX this better not have a decimal
PRUint32 wroteLen = 0;
if (readLen > real_bpr) {
do {
PRUint8 *line = (PRUint8*)data + i*real_bpr;
mFrame->SetImageData(line, real_bpr, (rownum++)*bpr);
nsRect r(0, rownum, width, 1);
mObserver->OnDataAvailable(nsnull, nsnull, mFrame, &r);
wroteLen += real_bpr ;
i++;
} while(dataLen >= real_bpr * (i+1));
}
mDataReceived += readLen; // don't double count previous data that is in 'dataLen'
mDataWritten += wroteLen;
PRUint32 dataLeft = dataLen - wroteLen;
if (dataLeft > 0) {
if (mPrevData) {
mPrevData = (char *)PR_Realloc(mPrevData, mDataLeft + dataLeft);
strncpy(mPrevData + mDataLeft, data+wroteLen, dataLeft);
mDataLeft += dataLeft;
} else {
mDataLeft = dataLeft;
mPrevData = (char *)PR_Malloc(mDataLeft);
strncpy(mPrevData, data+wroteLen, mDataLeft);
}
}
PR_FREEIF(buf);
return NS_OK;
}
/* [noscript] unsigned long writeSegments (in nsReadSegmentFun reader, in voidPtr closure, in unsigned long count); */
NS_IMETHODIMP nsPPMDecoder::WriteSegments(nsReadSegmentFun reader, void * closure, PRUint32 count, PRUint32 *_retval)
{
return NS_ERROR_NOT_IMPLEMENTED;
}
/* attribute boolean nonBlocking; */
NS_IMETHODIMP nsPPMDecoder::GetNonBlocking(PRBool *aNonBlocking)
{
return NS_ERROR_NOT_IMPLEMENTED;
}
NS_IMETHODIMP nsPPMDecoder::SetNonBlocking(PRBool aNonBlocking)
{
return NS_ERROR_NOT_IMPLEMENTED;
}
/* attribute nsIOutputStreamObserver observer; */
NS_IMETHODIMP nsPPMDecoder::GetObserver(nsIOutputStreamObserver * *aObserver)
{
return NS_ERROR_NOT_IMPLEMENTED;
}
NS_IMETHODIMP nsPPMDecoder::SetObserver(nsIOutputStreamObserver * aObserver)
{
return NS_ERROR_NOT_IMPLEMENTED;
}

View File

@@ -0,0 +1,67 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
*
* The contents of this file are subject to the Mozilla Public
* License Version 1.1 (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/MPL/
*
* 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.org code.
*
* The Initial Developer of the Original Code is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 2001 Netscape Communications Corporation.
* All Rights Reserved.
*
* Contributor(s):
* Stuart Parmenter <pavlov@netscape.com>
*/
#ifndef nsPPMDecoder_h__
#define nsPPMDecoder_h__
#include "imgIDecoder.h"
#include "nsCOMPtr.h"
#include "imgIContainer.h"
#include "imgIDecoderObserver.h"
#include "gfxIImageFrame.h"
#include "imgIRequest.h"
#define NS_PPMDECODER_CID \
{ /* e90bfa06-1dd1-11b2-8217-f38fe5d431a2 */ \
0xe90bfa06, \
0x1dd1, \
0x11b2, \
{0x82, 0x17, 0xf3, 0x8f, 0xe5, 0xd4, 0x31, 0xa2} \
}
class nsPPMDecoder : public imgIDecoder
{
public:
NS_DECL_ISUPPORTS
NS_DECL_IMGIDECODER
NS_DECL_NSIOUTPUTSTREAM
nsPPMDecoder();
virtual ~nsPPMDecoder();
private:
nsCOMPtr<imgIContainer> mImage;
nsCOMPtr<gfxIImageFrame> mFrame;
nsCOMPtr<imgIRequest> mRequest;
nsCOMPtr<imgIDecoderObserver> mObserver; // this is just qi'd from mRequest for speed
PRUint32 mDataReceived;
PRUint32 mDataWritten;
PRUint32 mDataLeft;
char *mPrevData;
};
#endif // nsPPMDecoder_h__

View File

@@ -0,0 +1,42 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
*
* The contents of this file are subject to the Mozilla Public
* License Version 1.1 (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/MPL/
*
* 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.org code.
*
* The Initial Developer of the Original Code is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 2001 Netscape Communications Corporation. All
* Rights Reserved.
*
* Contributor(s):
* Stuart Parmenter <pavlov@netscape.com>
*/
#include "nsIGenericFactory.h"
#include "nsIModule.h"
#include "nsPPMDecoder.h"
// objects that just require generic constructors
NS_GENERIC_FACTORY_CONSTRUCTOR(nsPPMDecoder)
static nsModuleComponentInfo components[] =
{
{ "ppm decoder",
NS_PPMDECODER_CID,
"@mozilla.org/image/decoder;2?type=image/x-portable-pixmap",
nsPPMDecoderConstructor, },
};
NS_IMPL_NSGETMODULE("nsPPMDecoderModule", components)

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@@ -0,0 +1,25 @@
#
# The contents of this file are subject to the Netscape Public
# License Version 1.1 (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.org 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.
#
# Contributor(s):
DEPTH=..\..
DIRS = public src decoders
!include $(DEPTH)\config\rules.mak

View File

@@ -0,0 +1,111 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
*
* The contents of this file are subject to the Mozilla Public
* License Version 1.1 (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/MPL/
*
* 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.org code.
*
* The Initial Developer of the Original Code is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 2001 Netscape Communications Corporation.
* All Rights Reserved.
*
* Contributor(s):
* Stuart Parmenter <pavlov@netscape.com>
*/
#include "prlog.h"
#include "nsString.h"
#if defined(PR_LOGGING)
extern PRLogModuleInfo *gImgLog;
class LogScope {
public:
LogScope(PRLogModuleInfo *aLog, void *from, const nsAReadableCString &fn) :
mLog(aLog), mFrom(from), mFunc(fn)
{
PR_LOG(mLog, PR_LOG_DEBUG, ("[this=%p] %s {ENTER}\n",
mFrom, mFunc.get()));
}
/* const char * constructor */
LogScope(PRLogModuleInfo *aLog, void *from, const nsAReadableCString &fn,
const nsLiteralCString &paramName, const char *paramValue) :
mLog(aLog), mFrom(from), mFunc(fn)
{
PR_LOG(mLog, PR_LOG_DEBUG, ("[this=%p] %s (%s=\"%s\") {ENTER}\n",
mFrom, mFunc.get(),
paramName.get(),
paramValue));
}
/* void ptr constructor */
LogScope(PRLogModuleInfo *aLog, void *from, const nsAReadableCString &fn,
const nsLiteralCString &paramName, const void *paramValue) :
mLog(aLog), mFrom(from), mFunc(fn)
{
PR_LOG(mLog, PR_LOG_DEBUG, ("[this=%p] %s (%s=%p) {ENTER}\n",
mFrom, mFunc.get(),
paramName.get(),
paramValue));
}
/* PRInt32 constructor */
LogScope(PRLogModuleInfo *aLog, void *from, const nsAReadableCString &fn,
const nsLiteralCString &paramName, PRInt32 paramValue) :
mLog(aLog), mFrom(from), mFunc(fn)
{
PR_LOG(mLog, PR_LOG_DEBUG, ("[this=%p] %s (%s=\"%d\") {ENTER}\n",
mFrom, mFunc.get(),
paramName.get(),
paramValue));
}
/* PRUint32 constructor */
LogScope(PRLogModuleInfo *aLog, void *from, const nsAReadableCString &fn,
const nsLiteralCString &paramName, PRUint32 paramValue) :
mLog(aLog), mFrom(from), mFunc(fn)
{
PR_LOG(mLog, PR_LOG_DEBUG, ("[this=%p] %s (%s=\"%d\") {ENTER}\n",
mFrom, mFunc.get(),
paramName.get(),
paramValue));
}
~LogScope() {
PR_LOG(mLog, PR_LOG_DEBUG, ("[this=%p] %s {EXIT}\n",
mFrom, mFunc.get()));
}
private:
PRLogModuleInfo *mLog;
void *mFrom;
nsCAutoString mFunc;
};
#define LOG_SCOPE(l, s) \
LogScope LOG_SCOPE_TMP_VAR ##__LINE__ (l, \
NS_STATIC_CAST(void *, this), \
NS_LITERAL_CSTRING(s))
#define LOG_SCOPE_WITH_PARAM(l, s, pn, pv) \
LogScope LOG_SCOPE_TMP_VAR ##__LINE__ (l, \
NS_STATIC_CAST(void *, this), \
NS_LITERAL_CSTRING(s), \
NS_LITERAL_CSTRING(pn), pv)
#else
#define LOG_SCOPE(l, s)
#define LOG_SCOPE_WITH_PARAM(l, s, pn, pv)
#endif

View File

@@ -0,0 +1 @@
ImageLogging.h

View File

@@ -0,0 +1,6 @@
imgIContainer.idl
imgIContainerObserver.idl
imgIDecoder.idl
imgIDecoderObserver.idl
imgILoader.idl
imgIRequest.idl

View File

@@ -0,0 +1,41 @@
#
# The contents of this file are subject to the Mozilla Public
# License Version 1.1 (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/MPL/
#
# 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.org code
#
# The Initial Developer of the Original Code is Netscape
# Communications Corporation. Portions created by Netscape are
# Copyright (C) 2001 Netscape Communications Corporation. All
# Rights Reserved.
#
# Contributor(s):
#
DEPTH = ../../..
topsrcdir = @top_srcdir@
srcdir = @srcdir@
VPATH = @srcdir@
include $(DEPTH)/config/autoconf.mk
MODULE = imglib2
EXPORTS = ImageLogging.h
XPIDLSRCS = imgIContainer.idl \
imgIContainerObserver.idl \
imgIDecoder.idl \
imgIDecoderObserver.idl \
imgILoader.idl \
imgIRequest.idl
include $(topsrcdir)/config/rules.mk

View File

@@ -0,0 +1,109 @@
/** -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
*
* The contents of this file are subject to the Mozilla Public
* License Version 1.1 (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/MPL/
*
* 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.org code.
*
* The Initial Developer of the Original Code is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 2001 Netscape Communications Corporation. All
* Rights Reserved.
*
* Contributor(s):
* Stuart Parmenter <pavlov@netscape.com>
*/
#include "nsISupports.idl"
#include "gfxtypes.idl"
#include "gfxIFormats.idl"
interface gfxIImageFrame;
interface nsIEnumerator;
interface imgIContainerObserver;
/**
* gfxIImageContainer interface
*
* @author Stuart Parmenter <pavlov@netscape.com>
* @version 0.1
* @see "gfx2"
*/
[scriptable, uuid(5e8405a4-1dd2-11b2-8385-bc8e3446cad3)]
interface imgIContainer : nsISupports
{
/**
* Create a new \a aWidth x \a aHeight sized image container.
*
* @param aWidth The width of the container in which all the
* gfxIImageFrame children will fit.
* @param aHeight The height of the container in which all the
* gfxIImageFrame children will fit.
* @param aObserver Observer to send animation notifications to.
*/
void init(in nscoord aWidth,
in nscoord aHeight,
in imgIContainerObserver aObserver);
/* this should probably be on the device context (or equiv) */
readonly attribute gfx_format preferredAlphaChannelFormat;
/**
* The width of the container rectangle.
*/
readonly attribute nscoord width;
/**
* The height of the container rectangle.
*/
readonly attribute nscoord height;
/**
* Get the current frame that would be drawn if the image was to be drawn now
*/
readonly attribute gfxIImageFrame currentFrame;
readonly attribute unsigned long numFrames;
gfxIImageFrame getFrameAt(in unsigned long index);
/**
* Adds \a item to the end of the list of frames.
* @param item frame to add.
*/
void appendFrame(in gfxIImageFrame item);
void removeFrame(in gfxIImageFrame item);
/* notification when the current frame is done decoding */
void endFrameDecode(in unsigned long framenumber, in unsigned long timeout);
/* notification that the entire image has been decoded */
void decodingComplete();
nsIEnumerator enumerate();
void clear();
void startAnimation();
void stopAnimation();
/* animation stuff */
/**
* number of times to loop the image.
* @note -1 means forever.
*/
attribute long loopCount;
};

View File

@@ -0,0 +1,46 @@
/** -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
*
* The contents of this file are subject to the Mozilla Public
* License Version 1.1 (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/MPL/
*
* 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.org code.
*
* The Initial Developer of the Original Code is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 2001 Netscape Communications Corporation. All
* Rights Reserved.
*
* Contributor(s):
* Stuart Parmenter <pavlov@netscape.com>
*/
#include "nsISupports.idl"
#include "gfxtypes.idl"
%{C++
#include "nsRect.h"
%}
interface imgIContainer;
interface gfxIImageFrame;
/**
* imgIContainerObserver interface
*
* @author Stuart Parmenter <pavlov@netscape.com>
* @version 0.1
*/
[uuid(153f1518-1dd2-11b2-b9cd-b16eb63e0471)]
interface imgIContainerObserver : nsISupports
{
[noscript] void frameChanged(in imgIContainer aContainer, in nsISupports aCX,
in gfxIImageFrame aFrame, in nsRect aDirtyRect);
};

View File

@@ -0,0 +1,53 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
*
* The contents of this file are subject to the Mozilla Public
* License Version 1.1 (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/MPL/
*
* 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.org code.
*
* The Initial Developer of the Original Code is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 2001 Netscape Communications Corporation.
* All Rights Reserved.
*
* Contributor(s):
* Stuart Parmenter <pavlov@netscape.com>
*/
#include "nsISupports.idl"
#include "nsIOutputStream.idl"
#include "gfxtypes.idl"
interface imgIRequest;
/**
* imgIDecoder interface
*
* @author Stuart Parmenter <pavlov@netscape.com>
* @version 0.1
* @see imagelib2
*/
[scriptable, uuid(9eebf43a-1dd1-11b2-953e-f1782f4cbad3)]
interface imgIDecoder : nsIOutputStream
{
/**
* Initalize an image decoder.
* @param aRequest the request that owns the decoder.
*
* @note The decode should QI \a aRequest to an imgIDecoderObserver
* and should send decoder notifications to the request.
* The decoder should always pass NULL as the first two parameters to
* all of the imgIDecoderObserver APIs.
*/
void init(in imgIRequest aRequest);
/// allows access to the nsIImage we have to put bits in to.
readonly attribute imgIRequest request;
};

View File

@@ -0,0 +1,80 @@
/** -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
*
* The contents of this file are subject to the Mozilla Public
* License Version 1.1 (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/MPL/
*
* 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.org code.
*
* The Initial Developer of the Original Code is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 2001 Netscape Communications Corporation. All
* Rights Reserved.
*
* Contributor(s):
* Stuart Parmenter <pavlov@netscape.com>
*/
#include "imgIContainerObserver.idl"
interface imgIRequest;
interface imgIContainer;
interface gfxIImageFrame;
%{C++
#include "nsRect.h"
%}
/**
* imgIDecoderObserver interface
*
* @author Stuart Parmenter <pavlov@netscape.com>
* @version 0.1
* @see imagelib2
*/
[scriptable, uuid(350163d2-1dd2-11b2-9e69-89959ecec1f3)]
interface imgIDecoderObserver : imgIContainerObserver
{
/**
* called as soon as the image begins getting decoded
*/
void onStartDecode(in imgIRequest aRequest, in nsISupports cx);
/**
* called once the image has been inited and therefore has a width and height
*/
void onStartContainer(in imgIRequest aRequest, in nsISupports cx, in imgIContainer aContainer);
/**
* called when each frame is created
*/
void onStartFrame(in imgIRequest aRequest, in nsISupports cx, in gfxIImageFrame aFrame);
/**
* called when some part of the frame has new data in it
*/
[noscript] void onDataAvailable(in imgIRequest aRequest, in nsISupports cx, in gfxIImageFrame aFrame, [const] in nsRect aRect);
/**
* called when a frame is finished decoding
*/
void onStopFrame(in imgIRequest aRequest, in nsISupports cx, in gfxIImageFrame aFrame);
/**
* probably not needed. called right before onStopDecode
*/
void onStopContainer(in imgIRequest aRequest, in nsISupports cx, in imgIContainer aContainer);
/**
* called when the decoder is dying off
*/
void onStopDecode(in imgIRequest aRequest, in nsISupports cx,
in nsresult status, in wstring statusArg);
};

View File

@@ -0,0 +1,62 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
*
* The contents of this file are subject to the Mozilla Public
* License Version 1.1 (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/MPL/
*
* 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.org code.
*
* The Initial Developer of the Original Code is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 2001 Netscape Communications Corporation.
* All Rights Reserved.
*
* Contributor(s):
* Stuart Parmenter <pavlov@netscape.com>
*/
#include "nsISupports.idl"
#include "gfxtypes.idl"
interface imgIDecoderObserver;
interface imgIRequest;
interface nsIChannel;
interface nsILoadGroup;
interface nsIStreamListener;
interface nsIURI;
interface nsISimpleEnumerator;
/**
* imgILoader interface
*
* @author Stuart Parmenter <pavlov@netscape.com>
* @version 0.1
* @see imagelib2
*/
[scriptable, uuid(4c8cf1e0-1dd2-11b2-aff9-c51cdbfcb6da)]
interface imgILoader : nsISupports
{
/**
* Start the load and decode of an image.
* @param uri the URI to load
* @param aObserver the observer
* @param cx some random data
*/
imgIRequest loadImage(in nsIURI uri, in nsILoadGroup aLoadGroup, in imgIDecoderObserver aObserver, in nsISupports cx);
/**
* Start the load and decode of an image.
* @param uri the URI to load
* @param aObserver the observer
* @param cx some random data
*/
imgIRequest loadImageWithChannel(in nsIChannel aChannel, in imgIDecoderObserver aObserver, in nsISupports cx, out nsIStreamListener aListener);
};

View File

@@ -0,0 +1,80 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
*
* The contents of this file are subject to the Mozilla Public
* License Version 1.1 (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/MPL/
*
* 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.org code.
*
* The Initial Developer of the Original Code is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 2001 Netscape Communications Corporation.
* All Rights Reserved.
*
* Contributor(s):
* Stuart Parmenter <pavlov@netscape.com>
*/
#include "nsISupports.idl"
#include "nsIRequest.idl"
interface imgIContainer;
interface imgIDecoderObserver;
interface nsIURI;
/**
* imgIRequest interface
*
* @author Stuart Parmenter <pavlov@netscape.com>
* @version 0.1
* @see imagelib2
*/
[scriptable, uuid(ccf705f6-1dd1-11b2-82ef-e18eccf7f7ec)]
interface imgIRequest : nsIRequest
{
/**
* the image container...
* @return the image object associated with the request.
* @attention NEED DOCS
*/
readonly attribute imgIContainer image;
/**
* Bits set in the return value from imageStatus
* @name statusflags
*/
//@{
const long STATUS_NONE = 0x0;
const long STATUS_SIZE_AVAILABLE = 0x1;
const long STATUS_LOAD_COMPLETE = 0x2;
const long STATUS_ERROR = 0x4;
//@}
/**
* something
* @attention NEED DOCS
*/
readonly attribute unsigned long imageStatus;
readonly attribute nsIURI URI;
readonly attribute imgIDecoderObserver decoderObserver;
};
%{C++
/**
* imagelib specific nsresult success and error codes
*/
#define NS_IMAGELIB_SUCCESS_LOAD_FINISHED NS_ERROR_GENERATE_SUCCESS(NS_ERROR_MODULE_IMGLIB, 0)
#define NS_IMAGELIB_ERROR_FAILURE NS_ERROR_GENERATE_FAILURE(NS_ERROR_MODULE_IMGLIB, 5)
#define NS_IMAGELIB_ERROR_NO_DECODER NS_ERROR_GENERATE_FAILURE(NS_ERROR_MODULE_IMGLIB, 6)
%}

View File

@@ -0,0 +1,43 @@
#
# The contents of this file are subject to the Mozilla Public
# License Version 1.1 (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/MPL/
#
# 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.org code
#
# The Initial Developer of the Original Code is Netscape
# Communications Corporation. Portions created by Netscape are
# Copyright (C) 2001 Netscape Communications Corporation. All
# Rights Reserved.
#
# Contributor(s):
# Stuart Parmenter <pavlov@netscape.com>
#
DEPTH = ..\..\..
include <$(DEPTH)/config/config.mak>
MODULE = imglib2
XPIDL_MODULE = imglib2
EXPORTS = ImageLogging.h
XPIDLSRCS = \
.\imgIContainer.idl \
.\imgIContainerObserver.idl \
.\imgIDecoder.idl \
.\imgIDecoderObserver.idl \
.\imgILoader.idl \
.\imgIRequest.idl \
$(NULL)
include <$(DEPTH)\config\rules.mak>

View File

@@ -0,0 +1,146 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
*
* The contents of this file are subject to the Mozilla Public
* License Version 1.1 (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/MPL/
*
* 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.org code.
*
* The Initial Developer of the Original Code is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 2001 Netscape Communications Corporation.
* All Rights Reserved.
*
* Contributor(s):
* Stuart Parmenter <pavlov@netscape.com>
*/
#include "DummyChannel.h"
#include "nsCOMPtr.h"
#include "nsIServiceManager.h"
NS_IMPL_ISUPPORTS1(DummyChannel, nsIChannel)
DummyChannel::DummyChannel(imgIRequest *aRequest, nsILoadGroup *aLoadGroup) :
mRequest(aRequest),
mLoadGroup(aLoadGroup),
mLoadFlags(nsIChannel::LOAD_NORMAL)
{
NS_INIT_ISUPPORTS();
/* member initializers and constructor code */
}
DummyChannel::~DummyChannel()
{
/* destructor code */
}
/* attribute nsIURI originalURI; */
NS_IMETHODIMP DummyChannel::GetOriginalURI(nsIURI * *aOriginalURI)
{
return mRequest->GetURI(aOriginalURI);
}
NS_IMETHODIMP DummyChannel::SetOriginalURI(nsIURI * aOriginalURI)
{
return NS_ERROR_FAILURE;
}
/* attribute nsIURI URI; */
NS_IMETHODIMP DummyChannel::GetURI(nsIURI * *aURI)
{
return mRequest->GetURI(aURI);
}
NS_IMETHODIMP DummyChannel::SetURI(nsIURI * aURI)
{
return NS_ERROR_FAILURE;
}
/* attribute nsISupports owner; */
NS_IMETHODIMP DummyChannel::GetOwner(nsISupports * *aOwner)
{
return NS_ERROR_NOT_IMPLEMENTED;
}
NS_IMETHODIMP DummyChannel::SetOwner(nsISupports * aOwner)
{
return NS_ERROR_NOT_IMPLEMENTED;
}
/* attribute nsILoadGroup loadGroup; */
NS_IMETHODIMP DummyChannel::GetLoadGroup(nsILoadGroup * *aLoadGroup)
{
*aLoadGroup = mLoadGroup;
NS_IF_ADDREF(*aLoadGroup);
return NS_OK;
}
NS_IMETHODIMP DummyChannel::SetLoadGroup(nsILoadGroup * aLoadGroup)
{
return NS_ERROR_FAILURE;
}
/* attribute nsLoadFlags loadAttributes; */
NS_IMETHODIMP DummyChannel::GetLoadAttributes(nsLoadFlags *aLoadAttributes)
{
*aLoadAttributes = mLoadFlags;
return NS_OK;
}
NS_IMETHODIMP DummyChannel::SetLoadAttributes(nsLoadFlags aLoadAttributes)
{
mLoadFlags = aLoadAttributes;
return NS_OK;
}
/* attribute nsIInterfaceRequestor notificationCallbacks; */
NS_IMETHODIMP DummyChannel::GetNotificationCallbacks(nsIInterfaceRequestor * *aNotificationCallbacks)
{
return NS_OK;
}
NS_IMETHODIMP DummyChannel::SetNotificationCallbacks(nsIInterfaceRequestor * aNotificationCallbacks)
{
return NS_OK;
}
/* readonly attribute nsISupports securityInfo; */
NS_IMETHODIMP DummyChannel::GetSecurityInfo(nsISupports * *aSecurityInfo)
{
return NS_ERROR_NOT_IMPLEMENTED;
}
/* attribute string contentType; */
NS_IMETHODIMP DummyChannel::GetContentType(char * *aContentType)
{
return NS_ERROR_NOT_IMPLEMENTED;
}
NS_IMETHODIMP DummyChannel::SetContentType(const char * aContentType)
{
return NS_ERROR_NOT_IMPLEMENTED;
}
/* attribute long contentLength; */
NS_IMETHODIMP DummyChannel::GetContentLength(PRInt32 *aContentLength)
{
return NS_ERROR_NOT_IMPLEMENTED;
}
NS_IMETHODIMP DummyChannel::SetContentLength(PRInt32 aContentLength)
{
return NS_ERROR_NOT_IMPLEMENTED;
}
/* nsIInputStream open (); */
NS_IMETHODIMP DummyChannel::Open(nsIInputStream **_retval)
{
return NS_ERROR_NOT_IMPLEMENTED;
}
/* void asyncOpen (in nsIStreamListener listener, in nsISupports ctxt); */
NS_IMETHODIMP DummyChannel::AsyncOpen(nsIStreamListener *listener, nsISupports *ctxt)
{
return NS_ERROR_NOT_IMPLEMENTED;
}

View File

@@ -0,0 +1,54 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
*
* The contents of this file are subject to the Mozilla Public
* License Version 1.1 (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/MPL/
*
* 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.org code.
*
* The Initial Developer of the Original Code is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 2001 Netscape Communications Corporation.
* All Rights Reserved.
*
* Contributor(s):
* Stuart Parmenter <pavlov@netscape.com>
*/
#ifndef DummyChannel_h__
#define DummyChannel_h__
#include "nsIChannel.h"
#include "nsIRequest.h"
#include "nsILoadGroup.h"
#include "imgIRequest.h"
#include "nsCOMPtr.h"
class DummyChannel : public nsIChannel
{
public:
NS_DECL_ISUPPORTS
NS_DECL_NSICHANNEL
NS_FORWARD_NSIREQUEST(mRequest->)
DummyChannel(imgIRequest *aRequest, nsILoadGroup *aLoadGroup);
~DummyChannel();
private:
/* additional members */
nsCOMPtr<imgIRequest> mRequest;
nsCOMPtr<nsILoadGroup> mLoadGroup;
nsLoadFlags mLoadFlags;
};
#endif

View File

@@ -0,0 +1,166 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
*
* The contents of this file are subject to the Mozilla Public
* License Version 1.1 (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/MPL/
*
* 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.org code.
*
* The Initial Developer of the Original Code is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 2001 Netscape Communications Corporation.
* All Rights Reserved.
*
* Contributor(s):
* Stuart Parmenter <pavlov@netscape.com>
*/
#include "ImageCache.h"
#ifdef MOZ_NEW_CACHE
#include "prlog.h"
#if defined(PR_LOGGING)
extern PRLogModuleInfo *gImgLog;
#else
#define gImgLog
#endif
#include "nsXPIDLString.h"
#include "nsCOMPtr.h"
#include "nsIServiceManager.h"
#include "nsICache.h"
#include "nsICacheService.h"
#include "nsICacheSession.h"
#include "nsICacheEntryDescriptor.h"
static nsCOMPtr<nsICacheSession> gSession = nsnull;
ImageCache::ImageCache()
{
/* member initializers and constructor code */
}
ImageCache::~ImageCache()
{
/* destructor code */
}
void GetCacheSession(nsICacheSession **_retval)
{
if (!gSession) {
nsCOMPtr<nsICacheService> cacheService(do_GetService("@mozilla.org/network/cache-service;1"));
NS_ASSERTION(cacheService, "Unable to get the cache service");
cacheService->CreateSession("images", nsICache::NOT_STREAM_BASED, PR_FALSE, getter_AddRefs(gSession));
NS_ASSERTION(gSession, "Unable to create a cache session");
}
*_retval = gSession;
NS_IF_ADDREF(*_retval);
}
void ImageCache::Shutdown()
{
gSession = nsnull;
}
PRBool ImageCache::Put(nsIURI *aKey, imgRequest *request, nsICacheEntryDescriptor **aEntry)
{
PR_LOG(gImgLog, PR_LOG_DEBUG,
("ImageCache::Put\n"));
nsresult rv;
nsCOMPtr<nsICacheSession> ses;
GetCacheSession(getter_AddRefs(ses));
nsXPIDLCString spec;
aKey->GetSpec(getter_Copies(spec));
nsCOMPtr<nsICacheEntryDescriptor> entry;
rv = ses->OpenCacheEntry(spec, nsICache::ACCESS_WRITE, getter_AddRefs(entry));
if (!entry || NS_FAILED(rv))
return PR_FALSE;
entry->SetCacheElement(NS_STATIC_CAST(nsISupports *, NS_STATIC_CAST(imgIRequest*, request)));
entry->MarkValid();
*aEntry = entry;
NS_ADDREF(*aEntry);
return PR_TRUE;
}
PRBool ImageCache::Get(nsIURI *aKey, imgRequest **aRequest, nsICacheEntryDescriptor **aEntry)
{
PR_LOG(gImgLog, PR_LOG_DEBUG,
("ImageCache::Get\n"));
nsresult rv;
nsCOMPtr<nsICacheSession> ses;
GetCacheSession(getter_AddRefs(ses));
nsXPIDLCString spec;
aKey->GetSpec(getter_Copies(spec));
nsCOMPtr<nsICacheEntryDescriptor> entry;
rv = ses->OpenCacheEntry(spec, nsICache::ACCESS_READ, getter_AddRefs(entry));
if (!entry || NS_FAILED(rv))
return PR_FALSE;
nsCOMPtr<nsISupports> sup;
entry->GetCacheElement(getter_AddRefs(sup));
nsCOMPtr<imgIRequest> req(do_QueryInterface(sup));
*aRequest = NS_REINTERPRET_CAST(imgRequest*, req.get());
NS_IF_ADDREF(*aRequest);
*aEntry = entry;
NS_ADDREF(*aEntry);
return PR_TRUE;
}
PRBool ImageCache::Remove(nsIURI *aKey)
{
PR_LOG(gImgLog, PR_LOG_DEBUG,
("ImageCache::Remove\n"));
nsresult rv;
nsCOMPtr<nsICacheSession> ses;
GetCacheSession(getter_AddRefs(ses));
nsXPIDLCString spec;
aKey->GetSpec(getter_Copies(spec));
nsCOMPtr<nsICacheEntryDescriptor> entry;
rv = ses->OpenCacheEntry(spec, nsICache::ACCESS_READ, getter_AddRefs(entry));
if (!entry || NS_FAILED(rv))
return PR_FALSE;
entry->Doom();
return PR_TRUE;
}
#endif /* MOZ_NEW_CACHE */

View File

@@ -0,0 +1,72 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
*
* The contents of this file are subject to the Mozilla Public
* License Version 1.1 (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/MPL/
*
* 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.org code.
*
* The Initial Developer of the Original Code is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 2001 Netscape Communications Corporation.
* All Rights Reserved.
*
* Contributor(s):
* Stuart Parmenter <pavlov@netscape.com>
*/
#ifndef ImageCache_h__
#define ImageCache_h__
#include "nsIURI.h"
#include "imgRequest.h"
#include "prtypes.h"
#ifdef MOZ_NEW_CACHE
#include "nsICacheEntryDescriptor.h"
#else
class nsICacheEntryDescriptor;
#endif
class ImageCache
{
public:
#ifdef MOZ_NEW_CACHE
ImageCache();
~ImageCache();
static void Shutdown(); // for use by the factory
/* additional members */
static PRBool Put(nsIURI *aKey, imgRequest *request, nsICacheEntryDescriptor **aEntry);
static PRBool Get(nsIURI *aKey, imgRequest **aRequest, nsICacheEntryDescriptor **aEntry);
static PRBool Remove(nsIURI *aKey);
#else
ImageCache() { }
~ImageCache() { }
static void Shutdown() { }
/* additional members */
static PRBool Put(nsIURI *aKey, imgRequest *request, nsICacheEntryDescriptor **aEntry) {
return PR_FALSE;
}
static PRBool Get(nsIURI *aKey, imgRequest **aRequest, nsICacheEntryDescriptor **aEntry) {
return PR_FALSE;
}
static PRBool Remove(nsIURI *aKey) {
return PR_FALSE;
}
#endif /* MOZ_NEW_CACHE */
};
#endif

View File

@@ -0,0 +1,67 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
*
* The contents of this file are subject to the Mozilla Public
* License Version 1.1 (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/MPL/
*
* 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.org code.
*
* The Initial Developer of the Original Code is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 2001 Netscape Communications Corporation. All
* Rights Reserved.
*
* Contributor(s):
* Stuart Parmenter <pavlov@netscape.com>
*/
#include "nsIGenericFactory.h"
#include "nsIModule.h"
#include "imgContainer.h"
#include "imgLoader.h"
#include "imgRequest.h"
#include "imgRequestProxy.h"
#include "ImageCache.h"
// objects that just require generic constructors
NS_GENERIC_FACTORY_CONSTRUCTOR(imgContainer)
NS_GENERIC_FACTORY_CONSTRUCTOR(imgLoader)
NS_GENERIC_FACTORY_CONSTRUCTOR(imgRequest)
NS_GENERIC_FACTORY_CONSTRUCTOR(imgRequestProxy)
static nsModuleComponentInfo components[] =
{
{ "image container",
NS_IMGCONTAINER_CID,
"@mozilla.org/image/container;1",
imgContainerConstructor, },
{ "image loader",
NS_IMGLOADER_CID,
"@mozilla.org/image/loader;1",
imgLoaderConstructor, },
{ "image request",
NS_IMGREQUEST_CID,
"@mozilla.org/image/request/real;1",
imgRequestConstructor, },
{ "image request proxy",
NS_IMGREQUESTPROXY_CID,
"@mozilla.org/image/request/proxy;1",
imgRequestProxyConstructor, },
};
PR_STATIC_CALLBACK(void)
ImageModuleDestructor(nsIModule *self)
{
ImageCache::Shutdown();
}
NS_IMPL_NSGETMODULE_WITH_DTOR("nsImageLib2Module", components, ImageModuleDestructor)

View File

@@ -0,0 +1,49 @@
#
# The contents of this file are subject to the Mozilla Public
# License Version 1.1 (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/MPL/
#
# 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.org code
#
# The Initial Developer of the Original Code is Netscape
# Communications Corporation. Portions created by Netscape are
# Copyright (C) 2001 Netscape Communications Corporation. All
# Rights Reserved.
#
# Contributor(s):
#
DEPTH = ../../..
topsrcdir = @top_srcdir@
srcdir = @srcdir@
VPATH = @srcdir@
include $(DEPTH)/config/autoconf.mk
MODULE = imglib2
LIBRARY_NAME = imglib2
IS_COMPONENT = 1
REQUIRES = xpcom string necko nkcache layout timer gfx2
CPPSRCS = \
DummyChannel.cpp \
ImageCache.cpp \
ImageFactory.cpp \
imgContainer.cpp \
imgLoader.cpp \
imgRequest.cpp \
imgRequestProxy.cpp
EXTRA_DSO_LDOPTS = \
$(MOZ_COMPONENT_LIBS) \
$(NULL)
include $(topsrcdir)/config/rules.mk

View File

@@ -0,0 +1,555 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
*
* The contents of this file are subject to the Mozilla Public
* License Version 1.1 (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/MPL/
*
* 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.org code.
*
* The Initial Developer of the Original Code is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 2001 Netscape Communications Corporation. All
* Rights Reserved.
*
* Contributor(s):
* Stuart Parmenter <pavlov@netscape.com>
* Chris Saari <saari@netscape.com>
*/
#include "imgContainer.h"
#include "nsIServiceManager.h"
#include "nsIInterfaceRequestor.h"
#include "gfxIImageFrame.h"
#include "nsIImage.h"
NS_IMPL_ISUPPORTS3(imgContainer, imgIContainer, nsITimerCallback,imgIDecoderObserver)
//******************************************************************************
imgContainer::imgContainer()
{
NS_INIT_ISUPPORTS();
/* member initializers and constructor code */
mCurrentDecodingFrameIndex = 0;
mCurrentAnimationFrameIndex = 0;
mCurrentFrameIsFinishedDecoding = PR_FALSE;
mDoneDecoding = PR_FALSE;
mAnimating = PR_FALSE;
mObserver = nsnull;
}
//******************************************************************************
imgContainer::~imgContainer()
{
if (mTimer)
mTimer->Cancel();
/* destructor code */
mFrames.Clear();
}
//******************************************************************************
/* void init (in nscoord aWidth, in nscoord aHeight, in imgIContainerObserver aObserver); */
NS_IMETHODIMP imgContainer::Init(nscoord aWidth, nscoord aHeight, imgIContainerObserver *aObserver)
{
if (aWidth <= 0 || aHeight <= 0) {
NS_WARNING("error - negative image size\n");
return NS_ERROR_FAILURE;
}
mSize.SizeTo(aWidth, aHeight);
mObserver = getter_AddRefs(NS_GetWeakReference(aObserver));
return NS_OK;
}
//******************************************************************************
/* readonly attribute gfx_format preferredAlphaChannelFormat; */
NS_IMETHODIMP imgContainer::GetPreferredAlphaChannelFormat(gfx_format *aFormat)
{
/* default.. platform's should probably overwrite this */
*aFormat = gfxIFormats::RGB_A8;
return NS_OK;
}
//******************************************************************************
/* readonly attribute nscoord width; */
NS_IMETHODIMP imgContainer::GetWidth(nscoord *aWidth)
{
*aWidth = mSize.width;
return NS_OK;
}
//******************************************************************************
/* readonly attribute nscoord height; */
NS_IMETHODIMP imgContainer::GetHeight(nscoord *aHeight)
{
*aHeight = mSize.height;
return NS_OK;
}
//******************************************************************************
/* readonly attribute gfxIImageFrame currentFrame; */
NS_IMETHODIMP imgContainer::GetCurrentFrame(gfxIImageFrame * *aCurrentFrame)
{
if(mCompositingFrame)
return mCompositingFrame->QueryInterface(NS_GET_IID(gfxIImageFrame), (void**)aCurrentFrame); // addrefs again
else
return this->GetFrameAt(mCurrentAnimationFrameIndex, aCurrentFrame);
}
//******************************************************************************
/* readonly attribute unsigned long numFrames; */
NS_IMETHODIMP imgContainer::GetNumFrames(PRUint32 *aNumFrames)
{
return mFrames.Count(aNumFrames);
}
//******************************************************************************
/* gfxIImageFrame getFrameAt (in unsigned long index); */
NS_IMETHODIMP imgContainer::GetFrameAt(PRUint32 index, gfxIImageFrame **_retval)
{
nsISupports *sup = mFrames.ElementAt(index); // addrefs
if (!sup)
return NS_ERROR_FAILURE;
nsresult rv;
rv = sup->QueryInterface(NS_GET_IID(gfxIImageFrame), (void**)_retval); // addrefs again
NS_RELEASE(sup);
return rv;
}
//******************************************************************************
/* void appendFrame (in gfxIImageFrame item); */
NS_IMETHODIMP imgContainer::AppendFrame(gfxIImageFrame *item)
{
// If we don't have a composite frame already allocated, make sure that our container
// size is the same the frame size. Otherwise, we'll either need the composite frame
// for animation compositing (GIF) or for filling in with a background color.
// XXX IMPORTANT: this means that the frame should be initialized BEFORE appending to container
PRUint32 numFrames;
this->GetNumFrames(&numFrames);
if(!mCompositingFrame) {
nsRect frameRect;
item->GetRect(frameRect);
// We used to create a compositing frame if any frame was smaller than the logical
// image size. You could create a single frame that was 10x10 in the middle of
// an 20x20 logical screen and have the extra screen space filled by the image
// background color. However, it turns out that neither NS4.x nor IE correctly
// support this, and as a result there are many GIFs out there that look "wrong"
// when this is correctly supported. So for now, we only create a compositing frame
// if we have more than one frame in the image.
if(/*(frameRect.x != 0) ||
(frameRect.y != 0) ||
(frameRect.width != mSize.width) ||
(frameRect.height != mSize.height) ||*/
(numFrames >= 1)) // Not sure if I want to create a composite frame for every anim. Could be smarter.
{
mCompositingFrame = do_CreateInstance("@mozilla.org/gfx/image/frame;2");
mCompositingFrame->Init(0, 0, mSize.width, mSize.height, gfxIFormats::RGB);
nsCOMPtr<nsIImage> img(do_GetInterface(mCompositingFrame));
img->SetDecodedRect(0, 0, mSize.width, mSize.height);
nsCOMPtr<gfxIImageFrame> firstFrame;
this->GetFrameAt(0, getter_AddRefs(firstFrame));
firstFrame->DrawTo(mCompositingFrame, 0, 0, mSize.width, mSize.height);
}
}
// If this is our second frame, init a timer so we don't display
// the next frame until the delay timer has expired for the current
// frame.
if (!mTimer && (numFrames >= 1)) {
PRInt32 timeout;
nsCOMPtr<gfxIImageFrame> currentFrame;
this->GetFrameAt(mCurrentDecodingFrameIndex, getter_AddRefs(currentFrame));
currentFrame->GetTimeout(&timeout);
if (timeout != -1 &&
timeout >= 0) { // -1 means display this frame forever
if(mAnimating) {
// Since we have more than one frame we need a timer
mTimer = do_CreateInstance("@mozilla.org/timer;1");
mTimer->Init(
NS_STATIC_CAST(nsITimerCallback*, this),
timeout, NS_PRIORITY_NORMAL, NS_TYPE_REPEATING_SLACK);
}
}
}
if (numFrames > 0) mCurrentDecodingFrameIndex++;
mCurrentFrameIsFinishedDecoding = PR_FALSE;
return mFrames.AppendElement(NS_STATIC_CAST(nsISupports*, item));
}
//******************************************************************************
/* void removeFrame (in gfxIImageFrame item); */
NS_IMETHODIMP imgContainer::RemoveFrame(gfxIImageFrame *item)
{
return NS_ERROR_NOT_IMPLEMENTED;
}
//******************************************************************************
/* void endFrameDecode (in gfxIImageFrame item, in unsigned long timeout); */
NS_IMETHODIMP imgContainer::EndFrameDecode(PRUint32 aFrameNum, PRUint32 aTimeout)
{
// It is now okay to start the timer for the next frame in the animation
mCurrentFrameIsFinishedDecoding = PR_TRUE;
nsCOMPtr<gfxIImageFrame> currentFrame;
this->GetFrameAt(aFrameNum-1, getter_AddRefs(currentFrame));
currentFrame->SetTimeout(aTimeout);
if (!mTimer && mAnimating){
PRUint32 numFrames;
this->GetNumFrames(&numFrames);
if (numFrames > 1) {
if (aTimeout != -1 &&
aTimeout >= 0) { // -1 means display this frame forever
mAnimating = PR_TRUE;
mTimer = do_CreateInstance("@mozilla.org/timer;1");
mTimer->Init(NS_STATIC_CAST(nsITimerCallback*, this),
aTimeout, NS_PRIORITY_NORMAL, NS_TYPE_REPEATING_SLACK);
}
}
}
return NS_OK;
}
//******************************************************************************
/* void decodingComplete (); */
NS_IMETHODIMP imgContainer::DecodingComplete(void)
{
mDoneDecoding = PR_TRUE;
return NS_OK;
}
//******************************************************************************
/* nsIEnumerator enumerate (); */
NS_IMETHODIMP imgContainer::Enumerate(nsIEnumerator **_retval)
{
return NS_ERROR_NOT_IMPLEMENTED;
}
/* void clear (); */
NS_IMETHODIMP imgContainer::Clear()
{
return mFrames.Clear();
}
//******************************************************************************
/* void startAnimation () */
NS_IMETHODIMP imgContainer::StartAnimation()
{
mAnimating = PR_TRUE;
if (mTimer)
return NS_OK;
PRUint32 numFrames;
this->GetNumFrames(&numFrames);
if (numFrames > 1) {
PRInt32 timeout;
nsCOMPtr<gfxIImageFrame> currentFrame;
this->GetCurrentFrame(getter_AddRefs(currentFrame));
if (currentFrame) {
currentFrame->GetTimeout(&timeout);
if (timeout != -1 &&
timeout >= 0) { // -1 means display this frame forever
mAnimating = PR_TRUE;
if(!mTimer) mTimer = do_CreateInstance("@mozilla.org/timer;1");
mTimer->Init(NS_STATIC_CAST(nsITimerCallback*, this),
timeout, NS_PRIORITY_NORMAL, NS_TYPE_REPEATING_SLACK);
}
} else {
// XXX hack.. the timer notify code will do the right thing, so just get that started
mAnimating = PR_TRUE;
if(!mTimer) mTimer = do_CreateInstance("@mozilla.org/timer;1");
mTimer->Init(NS_STATIC_CAST(nsITimerCallback*, this),
100, NS_PRIORITY_NORMAL, NS_TYPE_REPEATING_SLACK);
}
}
return NS_OK;
}
//******************************************************************************
/* void stopAnimation (); */
NS_IMETHODIMP imgContainer::StopAnimation()
{
mAnimating = PR_FALSE;
if (!mTimer)
return NS_OK;
mTimer->Cancel();
mTimer = nsnull;
// don't bother trying to change the frame (to 0, etc.) here.
// No one is listening.
return NS_OK;
}
//******************************************************************************
/* attribute long loopCount; */
NS_IMETHODIMP imgContainer::GetLoopCount(PRInt32 *aLoopCount)
{
return NS_ERROR_NOT_IMPLEMENTED;
}
NS_IMETHODIMP imgContainer::SetLoopCount(PRInt32 aLoopCount)
{
return NS_ERROR_NOT_IMPLEMENTED;
}
NS_IMETHODIMP_(void) imgContainer::Notify(nsITimer *timer)
{
NS_ASSERTION(mTimer == timer, "uh");
if(!mAnimating || !mTimer)
return;
nsCOMPtr<imgIContainerObserver> observer(do_QueryReferent(mObserver));
if (!observer) {
// the imgRequest that owns us is dead, we should die now too.
this->StopAnimation();
return;
}
nsCOMPtr<gfxIImageFrame> nextFrame;
PRInt32 timeout = 100;
PRUint32 numFrames;
GetNumFrames(&numFrames);
if(!numFrames)
return;
// If we're done decoding the next frame, go ahead and display it now and reinit
// the timer with the next frame's delay time.
PRUint32 previousAnimationFrameIndex = mCurrentAnimationFrameIndex;
if (mCurrentFrameIsFinishedDecoding && !mDoneDecoding) {
// If we have the next frame in the sequence set the timer callback from it
GetFrameAt(mCurrentAnimationFrameIndex+1, getter_AddRefs(nextFrame));
if (nextFrame) {
// Go to next frame in sequence
nextFrame->GetTimeout(&timeout);
mCurrentAnimationFrameIndex++;
} else {
// twiddle our thumbs
GetFrameAt(mCurrentAnimationFrameIndex, getter_AddRefs(nextFrame));
if(!nextFrame) return;
nextFrame->GetTimeout(&timeout);
}
} else if (mDoneDecoding){
if ((numFrames-1) == mCurrentAnimationFrameIndex) {
// Go back to the beginning of the animation
GetFrameAt(0, getter_AddRefs(nextFrame));
if(!nextFrame) return;
mCurrentAnimationFrameIndex = 0;
nextFrame->GetTimeout(&timeout);
} else {
mCurrentAnimationFrameIndex++;
GetFrameAt(mCurrentAnimationFrameIndex, getter_AddRefs(nextFrame));
if(!nextFrame) return;
nextFrame->GetTimeout(&timeout);
}
} else {
GetFrameAt(mCurrentAnimationFrameIndex, getter_AddRefs(nextFrame));
if(!nextFrame) return;
}
if(timeout >= 0)
mTimer->SetDelay(timeout);
else
this->StopAnimation();
nsRect dirtyRect;
// update the composited frame
if(mCompositingFrame && (previousAnimationFrameIndex != mCurrentAnimationFrameIndex)) {
nsCOMPtr<gfxIImageFrame> frameToUse;
DoComposite(getter_AddRefs(frameToUse), &dirtyRect, previousAnimationFrameIndex, mCurrentAnimationFrameIndex);
// do notification to FE to draw this frame, but hand it the compositing frame
observer->FrameChanged(this, nsnull, mCompositingFrame, &dirtyRect);
}
else {
nextFrame->GetRect(dirtyRect);
// do notification to FE to draw this frame
observer->FrameChanged(this, nsnull, nextFrame, &dirtyRect);
}
}
//******************************************************************************
// DoComposite gets called when the timer for animation get fired and we have to
// update the composited frame of the animation.
void imgContainer::DoComposite(gfxIImageFrame** aFrameToUse, nsRect* aDirtyRect, PRInt32 aPrevFrame, PRInt32 aNextFrame)
{
NS_ASSERTION(aDirtyRect, "DoComposite aDirtyRect is null");
NS_ASSERTION(mCompositingFrame, "DoComposite mCompositingFrame is null");
*aFrameToUse = nsnull;
PRUint32 numFrames;
this->GetNumFrames(&numFrames);
PRInt32 nextFrameIndex = aNextFrame;
PRInt32 prevFrameIndex = aPrevFrame;
if(nextFrameIndex >= numFrames) nextFrameIndex = numFrames-1;
if(prevFrameIndex >= numFrames) prevFrameIndex = numFrames-1;
nsCOMPtr<gfxIImageFrame> prevFrame;
this->GetFrameAt(prevFrameIndex, getter_AddRefs(prevFrame));
PRInt32 prevFrameDisposalMethod;
prevFrame->GetFrameDisposalMethod(&prevFrameDisposalMethod);
nsCOMPtr<gfxIImageFrame> nextFrame;
this->GetFrameAt(nextFrameIndex, getter_AddRefs(nextFrame));
PRInt32 x;
PRInt32 y;
PRInt32 width;
PRInt32 height;
nextFrame->GetX(&x);
nextFrame->GetY(&y);
nextFrame->GetWidth(&width);
nextFrame->GetHeight(&height);
switch (prevFrameDisposalMethod) {
default:
case 0: // DISPOSE_NOT_SPECIFIED
case 1: // DISPOSE_KEEP Leave previous frame in the framebuffer
mCompositingFrame->QueryInterface(NS_GET_IID(gfxIImageFrame), (void**)aFrameToUse); // addrefs again
//XXX blit into the composite frame too!!!
nextFrame->DrawTo(mCompositingFrame, x, y, width, height);
// we're drawing only the updated frame
(*aDirtyRect).x = x;
(*aDirtyRect).y = y;
(*aDirtyRect).width = width;
(*aDirtyRect).height = height;
break;
case 2: // DISPOSE_OVERWRITE_BGCOLOR Overwrite with background color
//XXX overwrite mCompositeFrame with background color
gfx_color backgroundColor;
nextFrame->GetBackgroundColor(&backgroundColor);
//XXX Do background color overwrite of mCompositeFrame here
// blit next frame into this clean slate
nextFrame->DrawTo(mCompositingFrame, x, y, width, height);
// In this case we need to blit the whole composite frame
(*aDirtyRect).x = 0;
(*aDirtyRect).y = 0;
(*aDirtyRect).width = mSize.width;
(*aDirtyRect).height = mSize.height;
mCompositingFrame->QueryInterface(NS_GET_IID(gfxIImageFrame), (void**)aFrameToUse); // addrefs again
break;
case 4: // DISPOSE_OVERWRITE_PREVIOUS Save-under
//XXX Reblit previous composite into frame buffer
//
(*aDirtyRect).x = 0;
(*aDirtyRect).y = 0;
(*aDirtyRect).width = mSize.width;
(*aDirtyRect).height = mSize.height;
break;
}
// Get the next frame's disposal method, if it is it DISPOSE_OVER, save off
// this mCompositeFrame for reblitting when this timer gets fired again and
// we
PRInt32 nextFrameDisposalMethod;
nextFrame->GetFrameDisposalMethod(&nextFrameDisposalMethod);
//XXX if(nextFrameDisposalMethod == 4)
// blit mPreviousCompositeFrame with this frame
}
//******************************************************************************
/* void onStartDecode (in imgIRequest aRequest, in nsISupports cx); */
NS_IMETHODIMP imgContainer::OnStartDecode(imgIRequest *aRequest, nsISupports *cx)
{
return NS_ERROR_NOT_IMPLEMENTED;
}
//******************************************************************************
/* void onStartContainer (in imgIRequest aRequest, in nsISupports cx, in imgIContainer aContainer); */
NS_IMETHODIMP imgContainer::OnStartContainer(imgIRequest *aRequest, nsISupports *cx, imgIContainer *aContainer)
{
return NS_ERROR_NOT_IMPLEMENTED;
}
//******************************************************************************
/* void onStartFrame (in imgIRequest aRequest, in nsISupports cx, in gfxIImageFrame aFrame); */
NS_IMETHODIMP imgContainer::OnStartFrame(imgIRequest *aRequest, nsISupports *cx, gfxIImageFrame *aFrame)
{
return NS_ERROR_NOT_IMPLEMENTED;
}
//******************************************************************************
/* [noscript] void onDataAvailable (in imgIRequest aRequest, in nsISupports cx, in gfxIImageFrame aFrame, [const] in nsRect aRect); */
NS_IMETHODIMP imgContainer::OnDataAvailable(imgIRequest *aRequest, nsISupports *cx, gfxIImageFrame *aFrame, const nsRect * aRect)
{
if(mCompositingFrame && !mCurrentDecodingFrameIndex) {
// Update the composite frame
PRInt32 x;
aFrame->GetX(&x);
aFrame->DrawTo(mCompositingFrame, x, aRect->y, aRect->width, aRect->height);
}
return NS_OK;
}
//******************************************************************************
/* void onStopFrame (in imgIRequest aRequest, in nsISupports cx, in gfxIImageFrame aFrame); */
NS_IMETHODIMP imgContainer::OnStopFrame(imgIRequest *aRequest, nsISupports *cx, gfxIImageFrame *aFrame)
{
return NS_ERROR_NOT_IMPLEMENTED;
}
//******************************************************************************
/* void onStopContainer (in imgIRequest aRequest, in nsISupports cx, in imgIContainer aContainer); */
NS_IMETHODIMP imgContainer::OnStopContainer(imgIRequest *aRequest, nsISupports *cx, imgIContainer *aContainer)
{
return NS_ERROR_NOT_IMPLEMENTED;
}
//******************************************************************************
/* void onStopDecode (in imgIRequest aRequest, in nsISupports cx, in nsresult status, in wstring statusArg); */
NS_IMETHODIMP imgContainer::OnStopDecode(imgIRequest *aRequest, nsISupports *cx, nsresult status, const PRUnichar *statusArg)
{
return NS_ERROR_NOT_IMPLEMENTED;
}
//******************************************************************************
/* [noscript] void frameChanged (in imgIContainer aContainer, in nsISupports aCX, in gfxIImageFrame aFrame, in nsRect aDirtyRect); */
NS_IMETHODIMP imgContainer::FrameChanged(imgIContainer *aContainer, nsISupports *aCX, gfxIImageFrame *aFrame, nsRect * aDirtyRect)
{
return NS_ERROR_NOT_IMPLEMENTED;
}

View File

@@ -0,0 +1,95 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
*
* The contents of this file are subject to the Mozilla Public
* License Version 1.1 (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/MPL/
*
* 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.org code.
*
* The Initial Developer of the Original Code is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 2001 Netscape Communications Corporation. All
* Rights Reserved.
*
* Contributor(s):
* Stuart Parmenter <pavlov@netscape.com>
* Chris Saari <saari@netscape.com>
*/
#ifndef __imgContainer_h__
#define __imgContainer_h__
#include "imgIContainer.h"
#include "imgIContainerObserver.h"
#include "nsSize.h"
#include "nsSupportsArray.h"
#include "nsCOMPtr.h"
#include "nsITimer.h"
#include "nsITimerCallback.h"
#include "imgIDecoderObserver.h"
#include "gfxIImageFrame.h"
#include "nsWeakReference.h"
#define NS_IMGCONTAINER_CID \
{ /* 5e04ec5e-1dd2-11b2-8fda-c4db5fb666e0 */ \
0x5e04ec5e, \
0x1dd2, \
0x11b2, \
{0x8f, 0xda, 0xc4, 0xdb, 0x5f, 0xb6, 0x66, 0xe0} \
}
class imgContainer : public imgIContainer,
public nsITimerCallback,
public imgIDecoderObserver
{
public:
NS_DECL_ISUPPORTS
NS_DECL_IMGICONTAINER
NS_DECL_IMGIDECODEROBSERVER
NS_DECL_IMGICONTAINEROBSERVER
NS_IMETHOD_(void) Notify(nsITimer *timer);
imgContainer();
virtual ~imgContainer();
private:
/* additional members */
nsSupportsArray mFrames;
nsSize mSize;
PRUint32 mCurrentDecodingFrameIndex; // 0 to numFrames-1
PRUint32 mCurrentAnimationFrameIndex; // 0 to numFrames-1
PRBool mCurrentFrameIsFinishedDecoding;
PRBool mDoneDecoding;
PRBool mAnimating;
nsWeakPtr mObserver;
// GIF specific bits
nsCOMPtr<nsITimer> mTimer;
// GIF animations will use the mCompositingFrame to composite images
// and just hand this back to the caller when it is time to draw the frame.
nsCOMPtr<gfxIImageFrame> mCompositingFrame;
// Private function for doing the frame compositing of animations and in cases
// where there is a backgound color and single frame placed withing a larger
// logical screen size. Smart GIF compressors may do this to save space.
void DoComposite(gfxIImageFrame** aFrameToUse, nsRect* aDirtyRect,
PRInt32 aPrevFrame, PRInt32 aNextFrame);
};
#endif /* __imgContainer_h__ */

View File

@@ -0,0 +1,242 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
*
* The contents of this file are subject to the Mozilla Public
* License Version 1.1 (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/MPL/
*
* 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.org code.
*
* The Initial Developer of the Original Code is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 2001 Netscape Communications Corporation.
* All Rights Reserved.
*
* Contributor(s):
* Stuart Parmenter <pavlov@netscape.com>
*/
#include "imgLoader.h"
#include "imgIRequest.h"
#include "nsIServiceManager.h"
#include "nsIChannel.h"
#include "nsIIOService.h"
#include "nsILoadGroup.h"
#include "nsIStreamListener.h"
#include "nsIURI.h"
#include "imgRequest.h"
#include "imgRequestProxy.h"
#include "ImageCache.h"
#include "nsXPIDLString.h"
#include "nsCOMPtr.h"
#include "ImageLogging.h"
NS_IMPL_ISUPPORTS1(imgLoader, imgILoader)
imgLoader::imgLoader()
{
NS_INIT_ISUPPORTS();
/* member initializers and constructor code */
}
imgLoader::~imgLoader()
{
/* destructor code */
}
/* imgIRequest loadImage (in nsIURI uri, in nsILoadGroup aLoadGroup, in imgIDecoderObserver aObserver, in nsISupports cx); */
NS_IMETHODIMP imgLoader::LoadImage(nsIURI *aURI, nsILoadGroup *aLoadGroup, imgIDecoderObserver *aObserver, nsISupports *cx, imgIRequest **_retval)
{
NS_ASSERTION(aURI, "imgLoader::LoadImage -- NULL URI pointer");
if (!aURI)
return NS_ERROR_NULL_POINTER;
#if defined(PR_LOGGING)
nsXPIDLCString spec;
aURI->GetSpec(getter_Copies(spec));
LOG_SCOPE_WITH_PARAM(gImgLog, "imgLoader::LoadImage", "aURI", spec.get());
#endif
imgRequest *request = nsnull;
#ifdef MOZ_NEW_CACHE
nsCOMPtr<nsICacheEntryDescriptor> entry;
ImageCache::Get(aURI, &request, getter_AddRefs(entry)); // addrefs request
if (request && entry && aLoadGroup) {
/* this isn't exactly what I want here. This code will re-doom every cache hit in a document while
it is force reloading. So for multiple copies of an image on a page, when you force reload, this
will cause you to get seperate loads for each copy of the image... this sucks.
*/
PRUint32 flags = 0;
PRBool doomRequest = PR_FALSE;
aLoadGroup->GetDefaultLoadAttributes(&flags);
if (flags & nsIChannel::FORCE_RELOAD)
doomRequest = PR_TRUE;
else {
nsCOMPtr<nsIRequest> r;
aLoadGroup->GetDefaultLoadRequest(getter_AddRefs(r));
if (r) {
nsCOMPtr<nsIChannel> c(do_QueryInterface(r));
if (c) {
c->GetLoadAttributes(&flags);
if (flags & nsIChannel::FORCE_RELOAD)
doomRequest = PR_TRUE;
}
}
}
if (doomRequest) {
entry->Doom(); // doom this thing.
entry = nsnull;
NS_RELEASE(request);
request = nsnull;
}
}
#endif
if (!request) {
/* no request from the cache. do a new load */
LOG_SCOPE(gImgLog, "imgLoader::LoadImage |cache miss|");
nsCOMPtr<nsIIOService> ioserv(do_GetService("@mozilla.org/network/io-service;1"));
if (!ioserv) return NS_ERROR_FAILURE;
nsCOMPtr<nsIChannel> newChannel;
ioserv->NewChannelFromURI(aURI, getter_AddRefs(newChannel));
if (!newChannel) return NS_ERROR_FAILURE;
if (aLoadGroup) {
PRUint32 flags;
aLoadGroup->GetDefaultLoadAttributes(&flags);
newChannel->SetLoadAttributes(flags);
}
NS_NEWXPCOM(request, imgRequest);
if (!request) return NS_ERROR_OUT_OF_MEMORY;
NS_ADDREF(request);
PR_LOG(gImgLog, PR_LOG_DEBUG,
("[this=%p] imgLoader::LoadImage -- Created new imgRequest [request=%p]\n", this, request));
#ifdef MOZ_NEW_CACHE
ImageCache::Put(aURI, request, getter_AddRefs(entry));
#endif
#ifdef MOZ_NEW_CACHE
request->Init(newChannel, entry);
#else
request->Init(newChannel, nsnull);
#endif
PR_LOG(gImgLog, PR_LOG_DEBUG,
("[this=%p] imgLoader::LoadImage -- Calling channel->AsyncOpen()\n", this));
// XXX are we calling this too early?
newChannel->AsyncOpen(NS_STATIC_CAST(nsIStreamListener *, request), nsnull);
} else {
/* request found in cache. use it */
PR_LOG(gImgLog, PR_LOG_DEBUG,
("[this=%p] imgLoader::LoadImage |cache hit| [request=%p]\n",
this, request));
}
PR_LOG(gImgLog, PR_LOG_DEBUG,
("[this=%p] imgLoader::LoadImage -- creating proxy request.\n", this));
imgRequestProxy *proxyRequest;
NS_NEWXPCOM(proxyRequest, imgRequestProxy);
if (!proxyRequest) return NS_ERROR_OUT_OF_MEMORY;
NS_ADDREF(proxyRequest);
// init adds itself to imgRequest's list of observers
proxyRequest->Init(request, aLoadGroup, aObserver, cx);
NS_RELEASE(request);
*_retval = NS_STATIC_CAST(imgIRequest*, proxyRequest);
NS_ADDREF(*_retval);
NS_RELEASE(proxyRequest);
return NS_OK;
}
/* imgIRequest loadImageWithChannel(in nsIChannel, in imgIDecoderObserver aObserver, in nsISupports cx, out nsIStreamListener); */
NS_IMETHODIMP imgLoader::LoadImageWithChannel(nsIChannel *channel, imgIDecoderObserver *aObserver, nsISupports *cx, nsIStreamListener **listener, imgIRequest **_retval)
{
NS_ASSERTION(channel, "imgLoader::LoadImageWithChannel -- NULL channel pointer");
imgRequest *request = nsnull;
nsCOMPtr<nsIURI> uri;
channel->GetOriginalURI(getter_AddRefs(uri));
#ifdef MOZ_NEW_CACHE
nsCOMPtr<nsICacheEntryDescriptor> entry;
ImageCache::Get(uri, &request, getter_AddRefs(entry)); // addrefs request
#endif
if (request) {
// we have this in our cache already.. cancel the current (document) load
// XXX
// if *listener is null when we return here, the caller should probably cancel
// the channel instead of us doing it here.
channel->Cancel(NS_BINDING_ABORTED); // this should fire an OnStopRequest
*listener = nsnull; // give them back a null nsIStreamListener
} else {
NS_NEWXPCOM(request, imgRequest);
if (!request) return NS_ERROR_OUT_OF_MEMORY;
NS_ADDREF(request);
#ifdef MOZ_NEW_CACHE
ImageCache::Put(uri, request, getter_AddRefs(entry));
#endif
#ifdef MOZ_NEW_CACHE
request->Init(channel, entry);
#else
request->Init(channel, nsnull);
#endif
*listener = NS_STATIC_CAST(nsIStreamListener*, request);
NS_IF_ADDREF(*listener);
}
imgRequestProxy *proxyRequest;
NS_NEWXPCOM(proxyRequest, imgRequestProxy);
if (!proxyRequest) return NS_ERROR_OUT_OF_MEMORY;
NS_ADDREF(proxyRequest);
// init adds itself to imgRequest's list of observers
proxyRequest->Init(request, nsnull, aObserver, cx);
NS_RELEASE(request);
*_retval = NS_STATIC_CAST(imgIRequest*, proxyRequest);
NS_ADDREF(*_retval);
NS_RELEASE(proxyRequest);
return NS_OK;
}

View File

@@ -0,0 +1,48 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
*
* The contents of this file are subject to the Mozilla Public
* License Version 1.1 (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/MPL/
*
* 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.org code.
*
* The Initial Developer of the Original Code is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 2001 Netscape Communications Corporation.
* All Rights Reserved.
*
* Contributor(s):
* Stuart Parmenter <pavlov@netscape.com>
*/
#include "imgILoader.h"
#ifdef LOADER_THREADSAFE
#include "prlock.h"
#endif
#define NS_IMGLOADER_CID \
{ /* 9f6a0d2e-1dd1-11b2-a5b8-951f13c846f7 */ \
0x9f6a0d2e, \
0x1dd1, \
0x11b2, \
{0xa5, 0xb8, 0x95, 0x1f, 0x13, 0xc8, 0x46, 0xf7} \
}
class imgLoader : public imgILoader
{
public:
NS_DECL_ISUPPORTS
NS_DECL_IMGILOADER
imgLoader();
virtual ~imgLoader();
private:
};

View File

@@ -0,0 +1,821 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
*
* The contents of this file are subject to the Mozilla Public
* License Version 1.1 (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/MPL/
*
* 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.org code.
*
* The Initial Developer of the Original Code is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 2001 Netscape Communications Corporation.
* All Rights Reserved.
*
* Contributor(s):
* Stuart Parmenter <pavlov@netscape.com>
*/
#include "imgRequest.h"
#include "nsIAtom.h"
#include "nsIChannel.h"
#include "nsILoadGroup.h"
#include "nsIHTTPChannel.h"
#include "nsIInputStream.h"
#include "imgILoader.h"
#include "nsIComponentManager.h"
#include "nsIComponentManager.h"
#include "nsIServiceManager.h"
#include "nsString.h"
#include "nsXPIDLString.h"
#include "gfxIImageFrame.h"
#ifdef MOZ_NEW_CACHE
#include "nsICachingChannel.h"
#endif
#include "ImageCache.h"
#include "ImageLogging.h"
#if defined(PR_LOGGING)
PRLogModuleInfo *gImgLog = PR_NewLogModule("imgRequest");
#endif
NS_IMPL_ISUPPORTS7(imgRequest, imgIRequest, nsIRequest,
imgIDecoderObserver, imgIContainerObserver,
nsIStreamListener, nsIStreamObserver,
nsISupportsWeakReference)
imgRequest::imgRequest() :
mObservers(0), mLoading(PR_FALSE), mProcessing(PR_FALSE), mStatus(imgIRequest::STATUS_NONE), mState(0)
{
NS_INIT_ISUPPORTS();
/* member initializers and constructor code */
}
imgRequest::~imgRequest()
{
/* destructor code */
}
nsresult imgRequest::Init(nsIChannel *aChannel, nsICacheEntryDescriptor *aCacheEntry)
{
// XXX we should save off the thread we are getting called on here so that we can proxy all calls to mDecoder to it.
PR_LOG(gImgLog, PR_LOG_DEBUG,
("[this=%p] imgRequest::Init\n", this));
NS_ASSERTION(!mImage, "imgRequest::Init -- Multiple calls to init");
NS_ASSERTION(aChannel, "imgRequest::Init -- No channel");
mChannel = aChannel;
#ifdef MOZ_NEW_CACHE
mCacheEntry = aCacheEntry;
#endif
// XXX do not init the image here. this has to be done from the image decoder.
mImage = do_CreateInstance("@mozilla.org/image/container;1");
return NS_OK;
}
nsresult imgRequest::AddObserver(imgIDecoderObserver *observer)
{
LOG_SCOPE_WITH_PARAM(gImgLog, "imgRequest::AddObserver", "observer", observer);
mObservers.AppendElement(NS_STATIC_CAST(void*, observer));
// OnStartDecode
if (mState & onStartDecode)
observer->OnStartDecode(nsnull, nsnull);
// OnStartContainer
if (mState & onStartContainer)
observer->OnStartContainer(nsnull, nsnull, mImage);
// Send frame messages (OnStartFrame, OnDataAvailable, OnStopFrame)
PRUint32 nframes;
mImage->GetNumFrames(&nframes);
if (nframes > 0) {
nsCOMPtr<gfxIImageFrame> frame;
// Is this a single frame image?
if (nframes == 1) {
// Get the first frame
mImage->GetFrameAt(0, getter_AddRefs(frame));
NS_ASSERTION(frame, "GetFrameAt gave back a null frame!");
} else if (nframes > 1) {
/* multiple frames, we'll use the current one */
mImage->GetCurrentFrame(getter_AddRefs(frame));
NS_ASSERTION(frame, "GetCurrentFrame gave back a null frame!");
}
// OnStartFrame
observer->OnStartFrame(nsnull, nsnull, frame);
if (!(mState & onStopContainer)) {
// OnDataAvailable
nsRect r;
frame->GetRect(r); // XXX we shouldn't send the whole rect here
observer->OnDataAvailable(nsnull, nsnull, frame, &r);
} else {
// OnDataAvailable
nsRect r;
frame->GetRect(r); // We're done loading this image, send the the whole rect
observer->OnDataAvailable(nsnull, nsnull, frame, &r);
// OnStopFrame
observer->OnStopFrame(nsnull, nsnull, frame);
}
}
// OnStopContainer
if (mState & onStopContainer)
observer->OnStopContainer(nsnull, nsnull, mImage);
nsresult status;
if (mStatus & imgIRequest::STATUS_LOAD_COMPLETE)
status = NS_IMAGELIB_SUCCESS_LOAD_FINISHED;
else if (mStatus & imgIRequest::STATUS_ERROR)
status = NS_IMAGELIB_ERROR_FAILURE;
// OnStopDecode
if (mState & onStopDecode)
observer->OnStopDecode(nsnull, nsnull, status, nsnull);
if (mImage && (mObservers.Count() == 1)) {
PRUint32 nframes;
mImage->GetNumFrames(&nframes);
PR_LOG(gImgLog, PR_LOG_DEBUG,
("[this=%p] imgRequest::AddObserver -- starting animation\n", this));
mImage->StartAnimation();
}
if (mState & onStopRequest) {
nsCOMPtr<nsIStreamObserver> ob(do_QueryInterface(observer));
PR_ASSERT(observer);
ob->OnStopRequest(nsnull, nsnull, status, nsnull);
}
return NS_OK;
}
nsresult imgRequest::RemoveObserver(imgIDecoderObserver *observer, nsresult status)
{
LOG_SCOPE_WITH_PARAM(gImgLog, "imgRequest::RemoveObserver", "observer", observer);
mObservers.RemoveElement(NS_STATIC_CAST(void*, observer));
if (mObservers.Count() == 0) {
if (mImage) {
PRUint32 nframes;
mImage->GetNumFrames(&nframes);
if (nframes > 1) {
PR_LOG(gImgLog, PR_LOG_DEBUG,
("[this=%p] imgRequest::RemoveObserver -- stopping animation\n", this));
mImage->StopAnimation();
}
}
if (mChannel && mLoading) {
PR_LOG(gImgLog, PR_LOG_DEBUG,
("[this=%p] imgRequest::RemoveObserver -- load in progress. canceling\n", this));
this->RemoveFromCache();
this->Cancel(NS_BINDING_ABORTED);
if (!(mState & onStopDecode)) {
// make sure that observer gets an onStopRequest message sent to it
observer->OnStopDecode(nsnull, nsnull, NS_IMAGELIB_ERROR_FAILURE, nsnull);
}
if (!(mState & onStopRequest)) {
// make sure that observer gets an onStopRequest message sent to it
nsCOMPtr<nsIStreamObserver> ob(do_QueryInterface(observer));
PR_ASSERT(observer);
ob->OnStopRequest(nsnull, nsnull, NS_BINDING_ABORTED, nsnull);
}
}
}
return NS_OK;
}
PRBool imgRequest::RemoveFromCache()
{
LOG_SCOPE(gImgLog, "imgRequest::RemoveFromCache");
#ifdef MOZ_NEW_CACHE
if (mCacheEntry) {
mCacheEntry->Doom();
mCacheEntry = nsnull;
} else {
NS_WARNING("imgRequest::RemoveFromCache -- no entry!");
}
#endif
return PR_TRUE;
}
/** nsIRequest / imgIRequest methods **/
/* readonly attribute wstring name; */
NS_IMETHODIMP imgRequest::GetName(PRUnichar * *aName)
{
NS_NOTYETIMPLEMENTED("imgRequest::GetName");
return NS_ERROR_NOT_IMPLEMENTED;
}
/* boolean isPending (); */
NS_IMETHODIMP imgRequest::IsPending(PRBool *_retval)
{
NS_NOTYETIMPLEMENTED("imgRequest::IsPending");
return NS_ERROR_NOT_IMPLEMENTED;
}
/* readonly attribute nsresult status; */
NS_IMETHODIMP imgRequest::GetStatus(nsresult *aStatus)
{
NS_NOTYETIMPLEMENTED("imgRequest::GetStatus");
return NS_ERROR_NOT_IMPLEMENTED;
}
/* void cancel (in nsresult status); */
NS_IMETHODIMP imgRequest::Cancel(nsresult status)
{
LOG_SCOPE(gImgLog, "imgRequest::Cancel");
if (mImage) {
PRUint32 nframes;
mImage->GetNumFrames(&nframes);
if (nframes > 1) {
PR_LOG(gImgLog, PR_LOG_DEBUG,
("[this=%p] imgRequest::RemoveObserver -- stopping animation\n", this));
mImage->StopAnimation();
}
}
if (mChannel && mLoading)
mChannel->Cancel(NS_BINDING_ABORTED); // should prolly use status here
return NS_OK;
}
/* void suspend (); */
NS_IMETHODIMP imgRequest::Suspend()
{
NS_NOTYETIMPLEMENTED("imgRequest::Suspend");
return NS_ERROR_NOT_IMPLEMENTED;
}
/* void resume (); */
NS_IMETHODIMP imgRequest::Resume()
{
NS_NOTYETIMPLEMENTED("imgRequest::Resume");
return NS_ERROR_NOT_IMPLEMENTED;
}
/** imgIRequest methods **/
/* readonly attribute imgIContainer image; */
NS_IMETHODIMP imgRequest::GetImage(imgIContainer * *aImage)
{
PR_LOG(gImgLog, PR_LOG_DEBUG,
("[this=%p] imgRequest::GetImage\n", this));
*aImage = mImage;
NS_IF_ADDREF(*aImage);
return NS_OK;
}
/* readonly attribute unsigned long imageStatus; */
NS_IMETHODIMP imgRequest::GetImageStatus(PRUint32 *aStatus)
{
PR_LOG(gImgLog, PR_LOG_DEBUG,
("[this=%p] imgRequest::GetImageStatus\n", this));
*aStatus = mStatus;
return NS_OK;
}
/* readonly attribute nsIURI URI; */
NS_IMETHODIMP imgRequest::GetURI(nsIURI **aURI)
{
PR_LOG(gImgLog, PR_LOG_DEBUG,
("[this=%p] imgRequest::GetURI\n", this));
if (mChannel)
return mChannel->GetOriginalURI(aURI);
else if (mURI) {
*aURI = mURI;
NS_ADDREF(*aURI);
return NS_OK;
}
return NS_ERROR_FAILURE;
}
/* readonly attribute imgIDecoderObserver decoderObserver; */
NS_IMETHODIMP imgRequest::GetDecoderObserver(imgIDecoderObserver **aDecoderObserver)
{
return NS_ERROR_FAILURE;
}
/** imgIContainerObserver methods **/
/* [noscript] void frameChanged (in imgIContainer container, in nsISupports cx, in gfxIImageFrame newframe, in nsRect dirtyRect); */
NS_IMETHODIMP imgRequest::FrameChanged(imgIContainer *container, nsISupports *cx, gfxIImageFrame *newframe, nsRect * dirtyRect)
{
LOG_SCOPE(gImgLog, "imgRequest::FrameChanged");
PRInt32 i = -1;
PRInt32 count = mObservers.Count();
while (++i < count) {
imgIDecoderObserver *ob = NS_STATIC_CAST(imgIDecoderObserver*, mObservers[i]);
if (ob) ob->FrameChanged(container, cx, newframe, dirtyRect);
}
return NS_OK;
}
/** imgIDecoderObserver methods **/
/* void onStartDecode (in imgIRequest request, in nsISupports cx); */
NS_IMETHODIMP imgRequest::OnStartDecode(imgIRequest *request, nsISupports *cx)
{
LOG_SCOPE(gImgLog, "imgRequest::OnStartDecode");
mState |= onStartDecode;
PRInt32 i = -1;
PRInt32 count = mObservers.Count();
while (++i < count) {
imgIDecoderObserver *ob = NS_STATIC_CAST(imgIDecoderObserver*, mObservers[i]);
if (ob) ob->OnStartDecode(request, cx);
}
return NS_OK;
}
/* void onStartContainer (in imgIRequest request, in nsISupports cx, in imgIContainer image); */
NS_IMETHODIMP imgRequest::OnStartContainer(imgIRequest *request, nsISupports *cx, imgIContainer *image)
{
LOG_SCOPE(gImgLog, "imgRequest::OnStartContainer");
mState |= onStartContainer;
mStatus |= imgIRequest::STATUS_SIZE_AVAILABLE;
PRInt32 i = -1;
PRInt32 count = mObservers.Count();
while (++i < count) {
imgIDecoderObserver *ob = NS_STATIC_CAST(imgIDecoderObserver*, mObservers[i]);
if (ob) ob->OnStartContainer(request, cx, image);
}
return NS_OK;
}
/* void onStartFrame (in imgIRequest request, in nsISupports cx, in gfxIImageFrame frame); */
NS_IMETHODIMP imgRequest::OnStartFrame(imgIRequest *request, nsISupports *cx, gfxIImageFrame *frame)
{
LOG_SCOPE(gImgLog, "imgRequest::OnStartFrame");
PRInt32 i = -1;
PRInt32 count = mObservers.Count();
while (++i < count) {
imgIDecoderObserver *ob = NS_STATIC_CAST(imgIDecoderObserver*, mObservers[i]);
if (ob) ob->OnStartFrame(request, cx, frame);
}
return NS_OK;
}
/* [noscript] void onDataAvailable (in imgIRequest request, in nsISupports cx, in gfxIImageFrame frame, [const] in nsRect rect); */
NS_IMETHODIMP imgRequest::OnDataAvailable(imgIRequest *request, nsISupports *cx, gfxIImageFrame *frame, const nsRect * rect)
{
LOG_SCOPE(gImgLog, "imgRequest::OnDataAvailable");
nsCOMPtr<imgIDecoderObserver> container = do_QueryInterface(mImage);
container->OnDataAvailable(request, cx, frame, rect);
PRInt32 i = -1;
PRInt32 count = mObservers.Count();
while (++i < count) {
imgIDecoderObserver *ob = NS_STATIC_CAST(imgIDecoderObserver*, mObservers[i]);
if (ob) ob->OnDataAvailable(request, cx, frame, rect);
}
return NS_OK;
}
/* void onStopFrame (in imgIRequest request, in nsISupports cx, in gfxIImageFrame frame); */
NS_IMETHODIMP imgRequest::OnStopFrame(imgIRequest *request, nsISupports *cx, gfxIImageFrame *frame)
{
NS_ASSERTION(frame, "imgRequest::OnStopFrame called with NULL frame");
LOG_SCOPE(gImgLog, "imgRequest::OnStopFrame");
PRInt32 i = -1;
PRInt32 count = mObservers.Count();
#ifdef MOZ_NEW_CACHE
if (mCacheEntry) {
PRUint32 cacheSize = 0;
mCacheEntry->GetDataSize(&cacheSize);
PRUint32 imageSize = 0;
PRUint32 alphaSize = 0;
frame->GetImageDataLength(&imageSize);
frame->GetAlphaDataLength(&alphaSize);
mCacheEntry->SetDataSize(cacheSize + imageSize + alphaSize);
}
#endif
while (++i < count) {
imgIDecoderObserver *ob = NS_STATIC_CAST(imgIDecoderObserver*, mObservers[i]);
if (ob) ob->OnStopFrame(request, cx, frame);
}
return NS_OK;
}
/* void onStopContainer (in imgIRequest request, in nsISupports cx, in imgIContainer image); */
NS_IMETHODIMP imgRequest::OnStopContainer(imgIRequest *request, nsISupports *cx, imgIContainer *image)
{
LOG_SCOPE(gImgLog, "imgRequest::OnStopContainer");
mState |= onStopContainer;
PRInt32 i = -1;
PRInt32 count = mObservers.Count();
while (++i < count) {
imgIDecoderObserver *ob = NS_STATIC_CAST(imgIDecoderObserver*, mObservers[i]);
if (ob) ob->OnStopContainer(request, cx, image);
}
return NS_OK;
}
/* void onStopDecode (in imgIRequest request, in nsISupports cx, in nsresult status, in wstring statusArg); */
NS_IMETHODIMP imgRequest::OnStopDecode(imgIRequest *aRequest, nsISupports *aCX, nsresult aStatus, const PRUnichar *aStatusArg)
{
LOG_SCOPE(gImgLog, "imgRequest::OnStopDecode");
if (mState & onStopDecode) {
NS_WARNING("OnStopDecode called multiple times.");
return NS_OK;
}
mState |= onStopDecode;
if (!(mStatus & imgIRequest::STATUS_ERROR) && NS_FAILED(aStatus))
mStatus |= imgIRequest::STATUS_ERROR;
PRInt32 i = -1;
PRInt32 count = mObservers.Count();
nsresult status;
if (mStatus & imgIRequest::STATUS_LOAD_COMPLETE)
status = NS_IMAGELIB_SUCCESS_LOAD_FINISHED;
else if (mStatus & imgIRequest::STATUS_ERROR)
status = NS_IMAGELIB_ERROR_FAILURE;
while (++i < count) {
imgIDecoderObserver *ob = NS_STATIC_CAST(imgIDecoderObserver*, mObservers[i]);
if (ob) ob->OnStopDecode(aRequest, aCX, status, aStatusArg);
}
return NS_OK;
}
/** nsIStreamObserver methods **/
/* void onStartRequest (in nsIRequest request, in nsISupports ctxt); */
NS_IMETHODIMP imgRequest::OnStartRequest(nsIRequest *aRequest, nsISupports *ctxt)
{
LOG_SCOPE(gImgLog, "imgRequest::OnStartRequest");
NS_ASSERTION(!mDecoder, "imgRequest::OnStartRequest -- we already have a decoder");
NS_ASSERTION(!mLoading, "imgRequest::OnStartRequest -- we are loading again?");
/* set our loading flag to true */
mLoading = PR_TRUE;
/* notify our kids */
PRInt32 i = -1;
PRInt32 count = mObservers.Count();
while (++i < count) {
imgIDecoderObserver *iob = NS_STATIC_CAST(imgIDecoderObserver*, mObservers[i]);
if (iob) {
nsCOMPtr<nsIStreamObserver> ob(do_QueryInterface(iob));
if (ob) ob->OnStartRequest(aRequest, ctxt);
}
}
/* do our real work */
nsCOMPtr<nsIChannel> chan(do_QueryInterface(aRequest));
if (!mChannel) {
PR_LOG(gImgLog, PR_LOG_ALWAYS,
(" `-> Channel already stopped or no channel!?.\n"));
return NS_ERROR_FAILURE;
}
nsCOMPtr<nsIHTTPChannel> httpChannel(do_QueryInterface(chan));
if (httpChannel) {
PRUint32 httpStatus;
httpChannel->GetResponseStatus(&httpStatus);
if (httpStatus == 404) {
PR_LOG(gImgLog, PR_LOG_DEBUG,
("[this=%p] imgRequest::OnStartRequest -- http status = 404. canceling.\n", this));
mStatus |= imgIRequest::STATUS_ERROR;
this->Cancel(NS_BINDING_ABORTED);
this->RemoveFromCache();
return NS_BINDING_ABORTED;
}
}
/* get the expires info */
#if defined(MOZ_NEW_CACHE)
if (mCacheEntry) {
nsCOMPtr<nsICachingChannel> cacheChannel(do_QueryInterface(chan));
if (cacheChannel) {
nsCOMPtr<nsISupports> cacheToken;
cacheChannel->GetCacheToken(getter_AddRefs(cacheToken));
if (cacheToken) {
nsCOMPtr<nsICacheEntryDescriptor> entryDesc(do_QueryInterface(cacheToken));
if (entryDesc) {
PRUint32 expiration;
/* get the expiration time from the caching channel's token */
entryDesc->GetExpirationTime(&expiration);
/* set the expiration time on our entry */
mCacheEntry->SetExpirationTime(expiration);
}
}
}
}
#endif
return NS_OK;
}
/* void onStopRequest (in nsIRequest request, in nsISupports ctxt, in nsresult status, in wstring statusArg); */
NS_IMETHODIMP imgRequest::OnStopRequest(nsIRequest *aRequest, nsISupports *ctxt, nsresult status, const PRUnichar *statusArg)
{
PR_LOG(gImgLog, PR_LOG_DEBUG,
("[this=%p] imgRequest::OnStopRequest\n", this));
NS_ASSERTION(mChannel && mLoading, "imgRequest::OnStopRequest -- received multiple OnStopRequest");
mState |= onStopRequest;
/* set our loading flag to false */
mLoading = PR_FALSE;
/* set our processing flag to false */
mProcessing = PR_FALSE;
#ifdef MOZ_NEW_CACHE
/* break the cycle from the cache entry. */
mCacheEntry = nsnull;
#endif
if (NS_FAILED(status)) {
mStatus |= imgIRequest::STATUS_ERROR;
this->RemoveFromCache();
this->Cancel(status); // stops animations
} else {
mStatus |= imgIRequest::STATUS_LOAD_COMPLETE;
}
mChannel->GetOriginalURI(getter_AddRefs(mURI));
mChannel = nsnull; // we no longer need the channel
if (mDecoder) {
mDecoder->Flush();
mDecoder->Close();
mDecoder = nsnull; // release the decoder so that it can rest peacefully ;)
}
/* notify the kids */
PRInt32 i = -1;
PRInt32 count = mObservers.Count();
while (++i < count) {
void *item = NS_STATIC_CAST(void *, mObservers[i]);
if (item) {
imgIDecoderObserver *iob = NS_STATIC_CAST(imgIDecoderObserver*, item);
if (iob) {
nsCOMPtr<nsIStreamObserver> ob(do_QueryInterface(iob));
if (ob) ob->OnStopRequest(aRequest, ctxt, status, statusArg);
}
}
}
// if there was an error loading the image, (mState & onStopDecode) won't be true.
// Send an onStopDecode message
if (!(mState & onStopDecode)) {
this->OnStopDecode(nsnull, nsnull, status, statusArg);
}
return NS_OK;
}
/* prototype for this defined below */
static NS_METHOD sniff_mimetype_callback(nsIInputStream* in, void* closure, const char* fromRawSegment,
PRUint32 toOffset, PRUint32 count, PRUint32 *writeCount);
/** nsIStreamListener methods **/
/* void onDataAvailable (in nsIRequest request, in nsISupports ctxt, in nsIInputStream inStr, in unsigned long sourceOffset, in unsigned long count); */
NS_IMETHODIMP imgRequest::OnDataAvailable(nsIRequest *aRequest, nsISupports *ctxt, nsIInputStream *inStr, PRUint32 sourceOffset, PRUint32 count)
{
PR_LOG(gImgLog, PR_LOG_DEBUG,
("[this=%p] imgRequest::OnDataAvailable\n", this));
NS_ASSERTION(mChannel, "imgRequest::OnDataAvailable -- no channel!");
if (!mProcessing) {
/* set our processing flag to true if this is the first OnDataAvailable() */
mProcessing = PR_TRUE;
/* look at the first few bytes and see if we can tell what the data is from that
* since servers tend to lie. :(
*/
PRUint32 out;
inStr->ReadSegments(sniff_mimetype_callback, this, count, &out);
#ifdef NS_DEBUG
/* NS_WARNING if the content type from the channel isn't the same if the sniffing */
#endif
if (!mContentType.get()) {
nsXPIDLCString contentType;
nsresult rv = mChannel->GetContentType(getter_Copies(contentType));
if (NS_FAILED(rv)) {
PR_LOG(gImgLog, PR_LOG_ERROR,
("[this=%p] imgRequest::OnStartRequest -- Content type unavailable from the channel\n",
this));
this->RemoveFromCache();
return NS_BINDING_ABORTED; //NS_BASE_STREAM_CLOSED;
}
mContentType = contentType;
}
#if defined(PR_LOGGING)
PR_LOG(gImgLog, PR_LOG_DEBUG,
("[this=%p] imgRequest::OnStartRequest -- Content type is %s\n", this, mContentType.get()));
#endif
nsCAutoString conid("@mozilla.org/image/decoder;2?type=");
conid += mContentType.get();
mDecoder = do_CreateInstance(conid);
if (!mDecoder) {
PR_LOG(gImgLog, PR_LOG_WARNING,
("[this=%p] imgRequest::OnStartRequest -- Decoder not available\n", this));
// no image decoder for this mimetype :(
this->Cancel(NS_BINDING_ABORTED);
this->RemoveFromCache();
// XXX notify the person that owns us now that wants the imgIContainer off of us?
return NS_IMAGELIB_ERROR_NO_DECODER;
}
mDecoder->Init(NS_STATIC_CAST(imgIRequest*, this));
}
if (!mDecoder) {
PR_LOG(gImgLog, PR_LOG_WARNING,
("[this=%p] imgRequest::OnDataAvailable -- no decoder\n", this));
return NS_BASE_STREAM_CLOSED;
}
PRUint32 wrote;
nsresult rv = mDecoder->WriteFrom(inStr, count, &wrote);
return NS_OK;
}
static NS_METHOD sniff_mimetype_callback(nsIInputStream* in,
void* closure,
const char* fromRawSegment,
PRUint32 toOffset,
PRUint32 count,
PRUint32 *writeCount)
{
imgRequest *request = NS_STATIC_CAST(imgRequest*, closure);
NS_ASSERTION(request, "request is null!");
if (count > 0)
request->SniffMimeType(fromRawSegment, count);
*writeCount = 0;
return NS_ERROR_FAILURE;
}
void
imgRequest::SniffMimeType(const char *buf, PRUint32 len)
{
/* Is it a GIF? */
if (len >= 4 && !nsCRT::strncmp(buf, "GIF8", 4)) {
mContentType = NS_LITERAL_CSTRING("image/gif");
return;
}
/* or a PNG? */
if (len >= 4 && ((unsigned char)buf[0]==0x89 &&
(unsigned char)buf[1]==0x50 &&
(unsigned char)buf[2]==0x4E &&
(unsigned char)buf[3]==0x47))
{
mContentType = NS_LITERAL_CSTRING("image/png");
return;
}
/* maybe a JPEG (JFIF)? */
/* JFIF files start with SOI APP0 but older files can start with SOI DQT
* so we test for SOI followed by any marker, i.e. FF D8 FF
* this will also work for SPIFF JPEG files if they appear in the future.
*
* (JFIF is 0XFF 0XD8 0XFF 0XE0 <skip 2> 0X4A 0X46 0X49 0X46 0X00)
*/
if (len >= 3 &&
((unsigned char)buf[0])==0xFF &&
((unsigned char)buf[1])==0xD8 &&
((unsigned char)buf[2])==0xFF)
{
mContentType = NS_LITERAL_CSTRING("image/jpeg");
return;
}
/* or how about ART? */
/* ART begins with JG (4A 47). Major version offset 2.
* Minor version offset 3. Offset 4 must be NULL.
*/
if (len >= 5 &&
((unsigned char) buf[0])==0x4a &&
((unsigned char) buf[1])==0x47 &&
((unsigned char) buf[4])==0x00 )
{
mContentType = NS_LITERAL_CSTRING("image/x-jg");
return;
}
/* none of the above? I give up */
}

View File

@@ -0,0 +1,113 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
*
* The contents of this file are subject to the Mozilla Public
* License Version 1.1 (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/MPL/
*
* 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.org code.
*
* The Initial Developer of the Original Code is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 2001 Netscape Communications Corporation.
* All Rights Reserved.
*
* Contributor(s):
* Stuart Parmenter <pavlov@netscape.com>
*/
#ifndef imgRequest_h__
#define imgRequest_h__
#include "imgIRequest.h"
#include "nsIRunnable.h"
#include "nsIChannel.h"
#include "nsIURI.h"
#include "imgIContainer.h"
#include "imgIDecoder.h"
#include "imgIDecoderObserver.h"
#include "nsIStreamListener.h"
#include "nsCOMPtr.h"
#include "nsVoidArray.h"
#include "nsWeakReference.h"
#include "nsString.h"
#ifdef MOZ_NEW_CACHE
#include "nsICacheEntryDescriptor.h"
#else
class nsICacheEntryDescriptor;
#endif
#define NS_IMGREQUEST_CID \
{ /* 9f733dd6-1dd1-11b2-8cdf-effb70d1ea71 */ \
0x9f733dd6, \
0x1dd1, \
0x11b2, \
{0x8c, 0xdf, 0xef, 0xfb, 0x70, 0xd1, 0xea, 0x71} \
}
enum {
onStartDecode = 0x1,
onStartContainer = 0x2,
onStopContainer = 0x4,
onStopDecode = 0x8,
onStopRequest = 0x16
};
class imgRequest : public imgIRequest,
public imgIDecoderObserver,
public nsIStreamListener,
public nsSupportsWeakReference
{
public:
imgRequest();
virtual ~imgRequest();
/* additional members */
nsresult Init(nsIChannel *aChannel, nsICacheEntryDescriptor *aCacheEntry);
nsresult AddObserver(imgIDecoderObserver *observer);
nsresult RemoveObserver(imgIDecoderObserver *observer, nsresult status);
PRBool RemoveFromCache();
void SniffMimeType(const char *buf, PRUint32 len);
NS_DECL_ISUPPORTS
NS_DECL_IMGIREQUEST
NS_DECL_NSIREQUEST
NS_DECL_IMGIDECODEROBSERVER
NS_DECL_IMGICONTAINEROBSERVER
NS_DECL_NSISTREAMLISTENER
NS_DECL_NSISTREAMOBSERVER
private:
nsCOMPtr<nsIChannel> mChannel;
nsCOMPtr<nsIURI> mURI;
nsCOMPtr<imgIContainer> mImage;
nsCOMPtr<imgIDecoder> mDecoder;
nsVoidArray mObservers;
PRBool mLoading;
PRBool mProcessing;
PRUint32 mStatus;
PRUint32 mState;
nsCString mContentType;
#ifdef MOZ_NEW_CACHE
nsCOMPtr<nsICacheEntryDescriptor> mCacheEntry; /* we hold on to this to this so long as we have observers */
#endif
};
#endif

View File

@@ -0,0 +1,316 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
*
* The contents of this file are subject to the Mozilla Public
* License Version 1.1 (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/MPL/
*
* 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.org code.
*
* The Initial Developer of the Original Code is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 2001 Netscape Communications Corporation.
* All Rights Reserved.
*
* Contributor(s):
* Stuart Parmenter <pavlov@netscape.com>
*/
#include "imgRequestProxy.h"
#include "nsXPIDLString.h"
#include "nsIInputStream.h"
#include "imgILoader.h"
#include "nsIComponentManager.h"
#include "nsIComponentManager.h"
#include "nsIServiceManager.h"
#include "imgRequest.h"
#include "nsString.h"
#include "DummyChannel.h"
#include "nspr.h"
#include "ImageLogging.h"
NS_IMPL_ISUPPORTS5(imgRequestProxy, imgIRequest, nsIRequest, imgIDecoderObserver, imgIContainerObserver, nsIStreamObserver)
imgRequestProxy::imgRequestProxy() :
mCanceled(PR_FALSE)
{
NS_INIT_ISUPPORTS();
/* member initializers and constructor code */
}
imgRequestProxy::~imgRequestProxy()
{
/* destructor code */
// XXX pav
// it isn't the job of the request proxy to cancel itself.
// if your object goes away and you want to cancel the load, then do it yourself.
// cancel here for now until i make this work right like the above comment
Cancel(NS_ERROR_FAILURE);
}
nsresult imgRequestProxy::Init(imgRequest *request, nsILoadGroup *aLoadGroup, imgIDecoderObserver *aObserver, nsISupports *cx)
{
PR_ASSERT(request);
LOG_SCOPE_WITH_PARAM(gImgLog, "imgRequestProxy::Init", "request", request);
mOwner = NS_STATIC_CAST(imgIRequest*, request);
mObserver = aObserver;
// XXX we should save off the thread we are getting called on here so that we can proxy all calls to mDecoder to it.
mContext = cx;
// XXX we should only create a channel, etc if the image isn't finished loading already.
nsISupports *inst = nsnull;
inst = new DummyChannel(this, aLoadGroup);
NS_ADDREF(inst);
nsresult res = inst->QueryInterface(NS_GET_IID(nsIChannel), getter_AddRefs(mDummyChannel));
NS_RELEASE(inst);
nsCOMPtr<nsILoadGroup> loadGroup;
mDummyChannel->GetLoadGroup(getter_AddRefs(loadGroup));
if (loadGroup) {
loadGroup->AddRequest(mDummyChannel, cx);
}
request->AddObserver(this);
return NS_OK;
}
/** nsIRequest / imgIRequest methods **/
/* readonly attribute wstring name; */
NS_IMETHODIMP imgRequestProxy::GetName(PRUnichar * *aName)
{
return NS_ERROR_NOT_IMPLEMENTED;
}
/* boolean isPending (); */
NS_IMETHODIMP imgRequestProxy::IsPending(PRBool *_retval)
{
return NS_ERROR_NOT_IMPLEMENTED;
}
/* readonly attribute nsresult status; */
NS_IMETHODIMP imgRequestProxy::GetStatus(nsresult *aStatus)
{
return NS_ERROR_NOT_IMPLEMENTED;
}
/* void cancel (in nsresult status); */
NS_IMETHODIMP imgRequestProxy::Cancel(nsresult status)
{
if (mCanceled)
return NS_ERROR_FAILURE;
LOG_SCOPE(gImgLog, "imgRequestProxy::Cancel");
mCanceled = PR_TRUE;
NS_ASSERTION(mOwner, "canceling request proxy twice");
nsresult rv = NS_REINTERPRET_CAST(imgRequest*, mOwner.get())->RemoveObserver(this, status);
mOwner = nsnull;
return rv;
}
/* void suspend (); */
NS_IMETHODIMP imgRequestProxy::Suspend()
{
return NS_ERROR_NOT_IMPLEMENTED;
}
/* void resume (); */
NS_IMETHODIMP imgRequestProxy::Resume()
{
return NS_ERROR_NOT_IMPLEMENTED;
}
/** imgIRequest methods **/
/* readonly attribute imgIContainer image; */
NS_IMETHODIMP imgRequestProxy::GetImage(imgIContainer * *aImage)
{
if (!mOwner)
return NS_ERROR_FAILURE;
return mOwner->GetImage(aImage);
}
/* readonly attribute unsigned long imageStatus; */
NS_IMETHODIMP imgRequestProxy::GetImageStatus(PRUint32 *aStatus)
{
if (!mOwner) {
*aStatus = imgIRequest::STATUS_ERROR;
return NS_ERROR_FAILURE;
}
return mOwner->GetImageStatus(aStatus);
}
/* readonly attribute nsIURI URI; */
NS_IMETHODIMP imgRequestProxy::GetURI(nsIURI **aURI)
{
if (!mOwner)
return NS_ERROR_FAILURE;
return mOwner->GetURI(aURI);
}
/* readonly attribute imgIDecoderObserver decoderObserver; */
NS_IMETHODIMP imgRequestProxy::GetDecoderObserver(imgIDecoderObserver **aDecoderObserver)
{
*aDecoderObserver = mObserver;
NS_IF_ADDREF(*aDecoderObserver);
return NS_OK;
}
/** imgIContainerObserver methods **/
/* [noscript] void frameChanged (in imgIContainer container, in nsISupports cx, in gfxIImageFrame newframe, in nsRect dirtyRect); */
NS_IMETHODIMP imgRequestProxy::FrameChanged(imgIContainer *container, nsISupports *cx, gfxIImageFrame *newframe, nsRect * dirtyRect)
{
PR_LOG(gImgLog, PR_LOG_DEBUG,
("[this=%p] imgRequestProxy::FrameChanged\n", this));
if (mObserver)
mObserver->FrameChanged(container, mContext, newframe, dirtyRect);
return NS_OK;
}
/** imgIDecoderObserver methods **/
/* void onStartDecode (in imgIRequest request, in nsISupports cx); */
NS_IMETHODIMP imgRequestProxy::OnStartDecode(imgIRequest *request, nsISupports *cx)
{
PR_LOG(gImgLog, PR_LOG_DEBUG,
("[this=%p] imgRequestProxy::OnStartDecode\n", this));
if (mObserver)
mObserver->OnStartDecode(this, mContext);
return NS_OK;
}
/* void onStartContainer (in imgIRequest request, in nsISupports cx, in imgIContainer image); */
NS_IMETHODIMP imgRequestProxy::OnStartContainer(imgIRequest *request, nsISupports *cx, imgIContainer *image)
{
PR_LOG(gImgLog, PR_LOG_DEBUG,
("[this=%p] imgRequestProxy::OnStartContainer\n", this));
if (mObserver)
mObserver->OnStartContainer(this, mContext, image);
return NS_OK;
}
/* void onStartFrame (in imgIRequest request, in nsISupports cx, in gfxIImageFrame frame); */
NS_IMETHODIMP imgRequestProxy::OnStartFrame(imgIRequest *request, nsISupports *cx, gfxIImageFrame *frame)
{
PR_LOG(gImgLog, PR_LOG_DEBUG,
("[this=%p] imgRequestProxy::OnStartFrame\n", this));
if (mObserver)
mObserver->OnStartFrame(this, mContext, frame);
return NS_OK;
}
/* [noscript] void onDataAvailable (in imgIRequest request, in nsISupports cx, in gfxIImageFrame frame, [const] in nsRect rect); */
NS_IMETHODIMP imgRequestProxy::OnDataAvailable(imgIRequest *request, nsISupports *cx, gfxIImageFrame *frame, const nsRect * rect)
{
PR_LOG(gImgLog, PR_LOG_DEBUG,
("[this=%p] imgRequestProxy::OnDataAvailable\n", this));
if (mObserver)
mObserver->OnDataAvailable(this, mContext, frame, rect);
return NS_OK;
}
/* void onStopFrame (in imgIRequest request, in nsISupports cx, in gfxIImageFrame frame); */
NS_IMETHODIMP imgRequestProxy::OnStopFrame(imgIRequest *request, nsISupports *cx, gfxIImageFrame *frame)
{
PR_LOG(gImgLog, PR_LOG_DEBUG,
("[this=%p] imgRequestProxy::OnStopFrame\n", this));
if (mObserver)
mObserver->OnStopFrame(this, mContext, frame);
return NS_OK;
}
/* void onStopContainer (in imgIRequest request, in nsISupports cx, in imgIContainer image); */
NS_IMETHODIMP imgRequestProxy::OnStopContainer(imgIRequest *request, nsISupports *cx, imgIContainer *image)
{
PR_LOG(gImgLog, PR_LOG_DEBUG,
("[this=%p] imgRequestProxy::OnStopContainer\n", this));
if (mObserver)
mObserver->OnStopContainer(this, mContext, image);
return NS_OK;
}
/* void onStopDecode (in imgIRequest request, in nsISupports cx, in nsresult status, in wstring statusArg); */
NS_IMETHODIMP imgRequestProxy::OnStopDecode(imgIRequest *request, nsISupports *cx, nsresult status, const PRUnichar *statusArg)
{
PR_LOG(gImgLog, PR_LOG_DEBUG,
("[this=%p] imgRequestProxy::OnStopDecode\n", this));
if (mObserver)
mObserver->OnStopDecode(this, mContext, status, statusArg);
return NS_OK;
}
/* void onStartRequest (in nsIRequest request, in nsISupports ctxt); */
NS_IMETHODIMP imgRequestProxy::OnStartRequest(nsIRequest *request, nsISupports *ctxt)
{
return NS_OK;
}
/* void onStopRequest (in nsIRequest request, in nsISupports ctxt, in nsresult statusCode, in wstring statusText); */
NS_IMETHODIMP imgRequestProxy::OnStopRequest(nsIRequest *request, nsISupports *ctxt, nsresult statusCode, const PRUnichar *statusText)
{
if (!mDummyChannel)
return NS_OK;
nsCOMPtr<nsILoadGroup> loadGroup;
mDummyChannel->GetLoadGroup(getter_AddRefs(loadGroup));
if (loadGroup) {
loadGroup->RemoveRequest(mDummyChannel, mContext, statusCode, statusText);
}
mDummyChannel = nsnull;
return NS_OK;
}

View File

@@ -0,0 +1,70 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
*
* The contents of this file are subject to the Mozilla Public
* License Version 1.1 (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/MPL/
*
* 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.org code.
*
* The Initial Developer of the Original Code is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 2001 Netscape Communications Corporation.
* All Rights Reserved.
*
* Contributor(s):
* Stuart Parmenter <pavlov@netscape.com>
*/
#include "imgRequest.h"
#include "imgIDecoderObserver.h"
#include "imgIContainer.h"
#include "imgIDecoder.h"
#include "nsIStreamObserver.h"
#include "nsIChannel.h"
#include "nsILoadGroup.h"
#include "nsCOMPtr.h"
#define NS_IMGREQUESTPROXY_CID \
{ /* 20557898-1dd2-11b2-8f65-9c462ee2bc95 */ \
0x20557898, \
0x1dd2, \
0x11b2, \
{0x8f, 0x65, 0x9c, 0x46, 0x2e, 0xe2, 0xbc, 0x95} \
}
class imgRequestProxy : public imgIRequest,
public imgIDecoderObserver,
public nsIStreamObserver
{
public:
NS_DECL_ISUPPORTS
NS_DECL_IMGIREQUEST
NS_DECL_NSIREQUEST
NS_DECL_IMGIDECODEROBSERVER
NS_DECL_IMGICONTAINEROBSERVER
NS_DECL_NSISTREAMOBSERVER
imgRequestProxy();
virtual ~imgRequestProxy();
/* additional members */
nsresult Init(imgRequest *request, nsILoadGroup *aLoadGroup, imgIDecoderObserver *aObserver, nsISupports *cx);
private:
nsCOMPtr<imgIDecoderObserver> mObserver;
nsCOMPtr<nsISupports> mContext;
nsCOMPtr<imgIRequest> mOwner;
nsCOMPtr<nsIChannel> mDummyChannel;
PRBool mCanceled;
};

View File

@@ -0,0 +1,56 @@
#!nmake
#
# The contents of this file are subject to the Mozilla Public
# License Version 1.1 (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/MPL/
#
# 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.org code
#
# The Initial Developer of the Original Code is Netscape
# Communications Corporation. Portions created by Netscape are
# Copyright (C) 2001 Netscape Communications Corporation. All
# Rights Reserved.
#
# Contributor(s):
# Stuart Parmenter <pavlov@netscape.com>
#
DEPTH=..\..\..
include <$(DEPTH)/config/config.mak>
MODULE = imglib2
LIBRARY_NAME = imglib2
DLL = $(OBJDIR)\$(LIBRARY_NAME).dll
MAKE_OBJ_TYPE = DLL
OBJS = \
.\$(OBJDIR)\DummyChannel.obj \
.\$(OBJDIR)\ImageCache.obj \
.\$(OBJDIR)\ImageFactory.obj \
.\$(OBJDIR)\imgContainer.obj \
.\$(OBJDIR)\imgLoader.obj \
.\$(OBJDIR)\imgRequest.obj \
.\$(OBJDIR)\imgRequestProxy.obj \
$(NULL)
LLIBS=\
$(LIBNSPR) \
$(DIST)\lib\xpcom.lib \
$(DIST)\lib\gkgfxwin.lib \
$(NULL)
include <$(DEPTH)\config\rules.mak>
install:: $(DLL)
$(MAKE_INSTALL) .\$(OBJDIR)\$(LIBRARY_NAME).dll $(DIST)\bin\components
$(MAKE_INSTALL) .\$(OBJDIR)\$(LIBRARY_NAME).lib $(DIST)\lib
clobber::
rm -f $(DIST)\bin\components\$(LIBRARY_NAME).dll
rm -f $(DIST)\lib\$(LIBRARY_NAME).lib

View File

@@ -0,0 +1,90 @@
?AddRef@imgRequestProxy@@UAGKXZ ; 143798
?Release@imgContainer@@UAGKXZ ; 120291
?OnDataAvailable@imgRequestProxy@@UAGIPAVimgIRequest@@PAVnsISupports@@PAVgfxIImageFrame@@PBUnsRect@@@Z ; 84442
?QueryInterface@imgContainer@@UAGIABUnsID@@PAPAX@Z ; 76980
?OnDataAvailable@imgContainer@@UAGIPAVimgIRequest@@PAVnsISupports@@PAVgfxIImageFrame@@PBUnsRect@@@Z ; 75604
?OnDataAvailable@imgRequest@@UAGIPAVimgIRequest@@PAVnsISupports@@PAVgfxIImageFrame@@PBUnsRect@@@Z ; 75604
?AddRef@DummyChannel@@UAGKXZ ; 45629
?QueryInterface@DummyChannel@@UAGIABUnsID@@PAPAX@Z ; 45310
?GetImage@imgRequest@@UAGIPAPAVimgIContainer@@@Z ; 41814
?Release@DummyChannel@@UAGKXZ ; 41716
?GetImage@imgRequestProxy@@UAGIPAPAVimgIContainer@@@Z ; 40453
?GetFrameAt@imgContainer@@UAGIIPAPAVgfxIImageFrame@@@Z ; 39613
?GetHeight@imgContainer@@UAGIPAH@Z ; 32348
?Release@imgRequest@@UAGKXZ ; 31603
?AddRef@imgRequest@@UAGKXZ ; 31603
?GetNumFrames@imgContainer@@UAGIPAI@Z ; 28342
?GetImageStatus@imgRequestProxy@@UAGIPAI@Z ; 27464
?Release@imgRequestProxy@@UAGKXZ ; 23383
?GetCurrentFrame@imgContainer@@UAGIPAPAVgfxIImageFrame@@@Z ; 19319
?QueryInterface@imgRequest@@UAGIABUnsID@@PAPAX@Z ; 16120
?assign_assuming_AddRef@nsCOMPtr_base@@IAEXPAVnsISupports@@@Z ; 13764
?FrameChanged@imgRequestProxy@@UAGIPAVimgIContainer@@PAVnsISupports@@PAVgfxIImageFrame@@PAUnsRect@@@Z ; 13455
?QueryInterface@imgRequestProxy@@UAGIABUnsID@@PAPAX@Z ; 10170
?Notify@imgContainer@@UAGXPAVnsITimer@@@Z ; 9611
??0nsQueryReferent@@QAE@PAVnsIWeakReference@@PAI@Z ; 9611
?FrameChanged@imgRequest@@UAGIPAVimgIContainer@@PAVnsISupports@@PAVgfxIImageFrame@@PAUnsRect@@@Z ; 9609
?DoComposite@imgContainer@@AAEXPAPAVgfxIImageFrame@@PAUnsRect@@HH@Z ; 9608
?GetLoadAttributes@DummyChannel@@UAGIPAI@Z ; 8258
?Cancel@imgRequestProxy@@UAGII@Z ; 7509
?GetLoadGroup@DummyChannel@@UAGIPAPAVnsILoadGroup@@@Z ; 7456
?GetURI@imgRequest@@UAGIPAPAVnsIURI@@@Z ; 5395
?GetURI@imgRequestProxy@@UAGIPAPAVnsIURI@@@Z ; 5395
?GetCacheSession@@YAXPAPAVnsICacheSession@@@Z ; 5165
?GetWidth@imgContainer@@UAGIPAH@Z ; 4675
?Release@imgLoader@@UAGKXZ ; 3791
?AddObserver@imgRequest@@QAEIPAVimgIDecoderObserver@@@Z ; 3789
?Get@ImageCache@@SAHPAVnsIURI@@PAPAVimgRequest@@PAPAVnsICacheEntryDescriptor@@@Z ; 3789
?RemoveObserver@imgRequest@@QAEIPAVimgIDecoderObserver@@I@Z ; 3789
?Init@imgRequestProxy@@QAEIPAVimgRequest@@PAVnsILoadGroup@@PAVimgIDecoderObserver@@PAVnsISupports@@@Z ; 3789
?QueryInterface@imgLoader@@UAGIABUnsID@@PAPAX@Z ; 3789
??0imgRequestProxy@@QAE@XZ ; 3789
??0DummyChannel@@QAE@PAVimgIRequest@@PAVnsILoadGroup@@@Z ; 3789
?LoadImage@imgLoader@@UAGIPAVnsIURI@@PAVnsILoadGroup@@PAVimgIDecoderObserver@@PAVnsISupports@@PAPAVimgIRequest@@@Z ; 3789
??1imgRequestProxy@@UAE@XZ ; 3667
??1DummyChannel@@QAE@XZ ; 3667
??_EimgRequestProxy@@UAEPAXI@Z ; 3667
?OnStopRequest@imgRequestProxy@@UAGIPAVnsIRequest@@PAVnsISupports@@IPBG@Z ; 3667
?OnStopDecode@imgRequestProxy@@UAGIPAVimgIRequest@@PAVnsISupports@@IPBG@Z ; 3652
?OnStartContainer@imgRequestProxy@@UAGIPAVimgIRequest@@PAVnsISupports@@PAVimgIContainer@@@Z ; 3652
?OnStopContainer@imgRequestProxy@@UAGIPAVimgIRequest@@PAVnsISupports@@PAVimgIContainer@@@Z ; 3652
?OnStartDecode@imgRequestProxy@@UAGIPAVimgIRequest@@PAVnsISupports@@@Z ; 3652
?OnStopFrame@imgRequestProxy@@UAGIPAVimgIRequest@@PAVnsISupports@@PAVgfxIImageFrame@@@Z ; 3491
?OnStartFrame@imgRequestProxy@@UAGIPAVimgIRequest@@PAVnsISupports@@PAVgfxIImageFrame@@@Z ; 3491
?OnStartRequest@imgRequestProxy@@UAGIPAVnsIRequest@@PAVnsISupports@@@Z ; 2714
?OnStopFrame@imgRequest@@UAGIPAVimgIRequest@@PAVnsISupports@@PAVgfxIImageFrame@@@Z ; 2082
?AppendFrame@imgContainer@@UAGIPAVgfxIImageFrame@@@Z ; 2082
?OnStartFrame@imgRequest@@UAGIPAVimgIRequest@@PAVnsISupports@@PAVgfxIImageFrame@@@Z ; 2082
?EndFrameDecode@imgContainer@@UAGIII@Z ; 1996
?StartAnimation@imgContainer@@UAGIXZ ; 1747
?OnDataAvailable@imgRequest@@UAGIPAVnsIRequest@@PAVnsISupports@@PAVnsIInputStream@@II@Z ; 1415
??0imgContainer@@QAE@XZ ; 1376
??1imgRequest@@UAE@XZ ; 1376
?OnStopRequest@imgRequest@@UAGIPAVnsIRequest@@PAVnsISupports@@IPBG@Z ; 1376
?Init@imgRequest@@QAEIPAVnsIChannel@@PAVnsICacheEntryDescriptor@@@Z ; 1376
??1imgContainer@@UAE@XZ ; 1376
?Put@ImageCache@@SAHPAVnsIURI@@PAVimgRequest@@PAPAVnsICacheEntryDescriptor@@@Z ; 1376
??_GimgRequest@@UAEPAXI@Z ; 1376
??_EimgContainer@@UAEPAXI@Z ; 1376
??0imgRequest@@QAE@XZ ; 1376
?OnStartRequest@imgRequest@@UAGIPAVnsIRequest@@PAVnsISupports@@@Z ; 1367
?OnStartContainer@imgRequest@@UAGIPAVimgIRequest@@PAVnsISupports@@PAVimgIContainer@@@Z ; 1361
?Init@imgContainer@@UAGIHHPAVimgIContainerObserver@@@Z ; 1361
?OnStartDecode@imgRequest@@UAGIPAVimgIRequest@@PAVnsISupports@@@Z ; 1361
?SniffMimeType@imgRequest@@QAEXPBDI@Z ; 1361
?OnStopContainer@imgRequest@@UAGIPAVimgIRequest@@PAVnsISupports@@PAVimgIContainer@@@Z ; 1361
?OnStopDecode@imgRequest@@UAGIPAVimgIRequest@@PAVnsISupports@@IPBG@Z ; 1361
?GetContentType@DummyChannel@@UAGIPAPAD@Z ; 1275
?DecodingComplete@imgContainer@@UAGIXZ ; 1275
?Cancel@DummyChannel@@UAGII@Z ; 122
?StopAnimation@imgContainer@@UAGIXZ ; 121
?GetDecoderObserver@imgRequestProxy@@UAGIPAPAVimgIDecoderObserver@@@Z ; 84
??0nsGetInterface@@QAE@PAVnsISupports@@PAI@Z ; 77
_NSGetModule ; 1
??_EimgLoader@@UAEPAXI@Z ; 1
??1imgLoader@@UAE@XZ ; 1
?Shutdown@ImageCache@@SAXXZ ; 1
??0imgLoader@@QAE@XZ ; 1
?do_GetService@@YA?BVnsGetServiceByContractID@@PBDPAI@Z ; 1
?Cancel@imgRequest@@UAGII@Z ; 1
?RemoveFromCache@imgRequest@@QAEHXZ ; 1

View File

@@ -1,46 +0,0 @@
Mstone building instructions
For Unix, just "gmake" one of these
release The usual optimized build
debug Debug build includes some asserts
rpackage Build the release and package it
dpackage Build the debug version and package it
all_OPT Build a multi-platform package
all_DBG Build a multi-platform debug package
For NT, run autobuild.bat. This will build and package both the debug
and optimized versions. Perl must already be built and installed in
\. The NT build may be behind the Unix stuff. Pull the build/package/*
subdirectories into the main build/package before doing a 'make all_???'.
You can build multiple OSes in the same tree. Debug and optimized
builds are kept separately. The all_??? targets will combine whatever
OSes are present into a multi-architecture package (including NT).
Note that you have ot build and package each OS before doing the all_
step.
Helper components
Linux usually comes with workable versions of gnuplot and perl. Most
other OSes don't. Mstone can build and package perl, gnuplot, and gd
with the right settings. These will be automatically built and
packaged if they are present.
Unpack gd1.3 or later in the mstone directory. You can probably find
gd from here: http://www.boutell.com/gd/. The directory should look
like gd?.*. Right now we need the (obsolete) version 1.3 to generate
GIF files (without patented run-length coding). The scripts need to
be updated to be able to handle PNG or GIF files.
Unpack gnuplot 3.7 or later in the mstone directory. You can probably
find gnuplot from http://www.cs.dartmouth.edu/gnuplot_info.html. The
directory should look like gnuplot-?.* (the exact version should not
matter). Gnuplot requres gd to generate GIFs (which is what we need).
Unpack perl 5.005 or later in the mstone directory. You can probably
find perl from http://www.perl.com/pub/language/info/software.html.
The directory should look like perl5.* (the exact version should
not matter).

View File

@@ -1,54 +0,0 @@
2004-06-14 Dan Christian <robodan@idiom.com>
* Makefile (VERSION): Bump version to 4.3
* Make build work on recent versions of Linux and Solaris
* Make ssh the default way to get a remote shell
* Support SVG graph output (not supported by all browsers)
* Use rfc822 style from addresses
* Fix documentation link on index page to be local
2000-04-28 Dan Christian <dac@x.cx>
* http and wmap now use common routines from http-util
* http is now separated from the pish command structure.
2000-04-27 Dan Christian <dac@x.cx>
* bin/genplot.pl: Support gnuplot generating images other than gif
* src/smtp.c (sendSMTPStart): Send domain name with HELO
2000-04-05 Dan Christian <robodan@netscape.com>
* Fix bug in WMAP where the login field was reporting banner data.
* Add a reconnect concept to WMAP. This separates out the
reconnect activity from the initial connections. There is still a
bug/feature that the reconnect increments an error which can
eventually hit the maxErrors limit. You have to record the error
or else you could not get the "connections" graph right.
2000-03-31 Dan Christian <robodan@netscape.com>
* Merged setup and mstone into one script to reduce command
namespace polution. "mstone setup" is the the same as "setup".
* Made setup try to be more tolerant of OSes that were not
include in the distribution. SunOS 5.7 will fall back to 5.6.
* Now package conf/general.wld.in and only copy to general.wld if
there isn't one already in place. This means that you can unpack
new bits over old bits without blowing away your configuration.
* Added <includeOnce file> command to workloads. This allows
tests to be used either as a stand alone or as part of another
test (e.g. smtp).
* Converted ChangeLog to more common formating
* Spilt off old ChangeLog entries to ChangeLog.1 and ChangeLog.2

View File

@@ -1,129 +0,0 @@
MailStone 4.1: Changes to since version 4.0
* threads are used on all platforms reduces memory requirements by
10x for large numbers of clients must run as root for maximum
connections per process
* massive internal code and script cleanup / rewrite performance
improvements for socket handling (blocking) and caching files and
name lookups
* filename and path conventions restructuring '/mailstone'
hardwired path no longer required mailstone/results/index.html
(index of test runs) mailstone/results/<datestamp>/stderr (look
here for errors) mailstone/results/<datestamp>/results.html
mailstone/results/<datestamp>/results.txt
mailstone/results/<datestamp>/work.wld (workload config used)
mailstone/results/<datestamp>/testbed.tbd (testbed used)
mailstone/results/<datestamp>/summary.csv (per client summary)
mailstone/results/<datestamp>/*.gif (graphs)
mailstone/tmp/<datestamp>/*.out (raw results from each client)
mailstone/conf/*.wld (workload file) mailstone/conf/*.html
(machine descriptions for reports) mailstone/data/*.msg (sample
test messages)
* periodic statistics reporting allows for trend analysis of many
variables per protocol. sampling rate is automatically determined
by mailmaster Can now generate on-the-fly reports for above by
running "process"
* The accountFormat directive is now obsolete. Use loginFormat
and addressFormat instead.
* The numAccounts and beginAccounts directives are now obsolete.
Use numLogins, firstLogin, numAddresses, and firstAddress instead.
* The sequentialLogins directive disables random account number
selection. This insures a predictable account sequence.
* The checkMailInterval directive for IMAP is now obsolete. Use
loopDelay instead.
* The directives idleTime, loopDelay, and numLoops now apply to
all protocols. See the manual for how loopDelay and numLoops are
used by each protocol.
* a command directive such as <SMTP> without HOSTS=xxx will now
apply to all clients in the testbed
* <include> directive for workload and testbed files (e.g. for
user profile)
* workloads are now passed to 'mailclient' through stdin no test
specific files need to be copied to client machines more
synchonized test startup
* 'setup' script will copy mailclient and test messages
(data/*.msg) to each testbed machine in /var/tmp
* 'cleanup' form of setup will remove mailclient and test messages
from each testbed machine in /var/tmp
* 'checktime' form of setup will (nearly) simultaneously retrieve
time from each client. This lets you easily check for clock
problems.
* 'timesync' form of setup will (nearly) simultaneously set time
on each client. This only works on OSs that support setting
seconds through the "date" command. rdate or ntpdate should be
used if available. You must be the root user and be able to rsh
as root for timesync to work.
* Improved reports in text and html (formatting and content)
* The text version of the report is now only displayed
automatically if "-v" is given.
* Graphs with more than one protocol will also display a "Total"
graph
* The graphs can now be customized for each test (see sample.wld
for the default)
* You can now add graphs (in addition to the default or configured
ones) by using "process timestamp -a conf/moregraph.wld".
* An informative index of test runs is now generated in
results/index.html
* The index is updated while the run is in progress to make
checking for errors easier.
* The error log now displays times relative to test start.
* Memory use while processing results has been greatly reduced.
* A summary of the data from each process is now saved in a
Comma-separated-value (CSV) file. results/timestamp/clients.csv
* A summary of the data over time is now saved in a
Comma-separated-value (CSV) file.
results/timestamp/protocol-time.csv
* new gnuplot binary included, can output directly to gif format
* read and write performance numbers now reported separately
* new runtime banners and copyrights (ooh boy)
* idleTime option for IMAP fixed, plus now applies to all commands
* blockTime now sets a delay between command blocks
* Process model is as follows
User runs the top-level 'mstone' script
This calls 'conf/testname.pl' with command line arguments
This calls 'mailmaster.pl' with config and command line arguments
mailmaster uses 'rsh' or equivalent to launch mailclients
mailclient runs on each testbed and forks numprocs
each proc spawns numthreads (one per client)
<run tests> (note: results are being sent continuously)
threads send results back through sockets to top mailclient
mailclient forwards results back over stdout via rsh pipe
(for future work - do some data reduction/combining here)
mailmaster directs output to each client-<hostname> file
mailmaster launches report generator
* sample LDIF fragment for a postmaster entry included

View File

@@ -1,77 +0,0 @@
MailStone 4.15: Changes to Mailstone since version 4.1
* Setup now checks license acceptance and configures a basic
setup. By default, it will also create a user LDIF file with a
'allusers' account.
* All parameters and and testbed information may now be specified
in the workload files (*.wld). New sections: CONFIG, CLIENT,
MONITOR, PRETEST, and POSTTEST. Command line parameters still
override the files. A complete copy of the configuration is saved
in results/<TIMESTAMP>/all.wld.
* The '*.pl', '*.tbd', and 'config*' files in ./conf/ are
depreciated. These should still work, but the new sections are
simpler and more flexible.
* Any CONFIG parameter can now be specified on the command line
using the form: 'PARAMETER=value'. Note that PARAMETER is case
insensitive. No whitespace is allowed before or after the '='.
* The new switch '-l' or CONFIG parameter 'ClientCount' can now
specify the total number of clients. The 'MaxClients' and
'MaxThreads' parameters in each CLIENT section control load
balancing. If the 'processes' and 'threads' parameters are set,
then the load for that CLIENT section will not be adjusted, but
will be taken into account when calculating other CLIENT sections.
If just 'processes' is set, then only the thread count will be
adjusted. All hosts in a CLIENT section will run the same number
of processes and threads.
* bin/makeusers.pl now creates users, broadcast account, etc.
Numbered passwords are now suppored. The new user/password format
now replaces '%ld' with the user number to match the rest of
mailstone. The ldif/ directory is obsolete. Run "perl/bin/perl
bin/makeusers.pl -h" for usage.
* NT client machines may now be used from a Unix test master. See
conf/sample.wld for configuration details.
* Commands can now be run for a specified block count, error
count, or time (whichever comes first). Set 'maxBlocks' and/or
'maxErrors'.
* Telemetry logging to /var/tmp/mstone-log.pn.tn is now performed
when "telemetry 1" is specified.
* The name used in the "CLIENT" section is now used to match
"HOSTS=..." qualifier. Compatibility with "hostname" is no longer
needed.
* Config values can now use quoted characters such as \n, \r, \t
* Config values can be continued using \ (backslash)
* System configuration information (SYSCONFIG) can now be
specified entirely within a workload file by quoting the newlines.
* Config values get enclosing double-quotes stripped
* Preliminary support for HTTP and WMAP (WebMail) testing.
* New table formats are easier to interpret and allow more protocols.
* The new text format report is easier to machine processes.
* The following command line switches are now obsolete: -f, -g,
-e, -p, and -l. The same functionality can be obtained by
FREQUENCY=<interval>, GNUPLOT=<path>, RSH=<path>, RCP=<path>, and
TEMPDIR=<directory> respectively.
* File backups are now created. When ./process is run multiple
times, the old files are moved to the ./tmp/<TIMESTAMP>/
directory.
* perl has been updated to include full perl5.005_03 install
package. Perl support for each architecture is now under the
perl/ directory.

View File

@@ -1,222 +0,0 @@
Mstone 4.15 Quick Installation
This version of Mstone runs on many current UNIX platforms and NT.
Only a web browser and text editor are needed to view the results and
configure tests.
QUICK INSTALL
-------------
IMPORTANT: If you have an existing mstone, save a copy of the
mstone/conf directory to preserve any configuration files you may want
to keep.
Unpack distribution:
tar xzf /tmp/mstone_OPT.tar.gz
or
gunzip -c /tmp/mstone_OPT.tar.gz | tar xf -
or
unzip /tmp/mstone_OPT.zip
cd mstone
Both the tar.gz file and the zip file are identical. Use whichever is
more convenient for you.
This will create a sub-directory named "mstone" with files and
directories under that.
cd mstone
NOTE: all scripts must be run from the mstone directory.
Do initial configuration:
Run "mstone config". It will ask you about your system configuration.
Fill in the appropriate values and create the optional user accounts
and broadcast account. When it asks about client machines, enter them
seperated by commas, with no spaces (e.g. host1,host2,host3). If you
need to re-configure, run "mstone config".
The machine starting the test may also be a client. For accurate
results, clients should not be run on the test mailserver machine (or
its directory server). If all the client machines are not running
the same operating system version, see "Configuring Client Machines"
below to configure for different OSes.
When the test master is on NT, only the local machine may be a client
and only one process is allowed. You will not be asked about client
machines.
Setup only configures the most important parameters. If you have more
advanced needs, edit conf/general.wld appropriately.
Run "mstone setup". It will now push the necessary files to each
client machine. If there are problems (i.e. with rsh permissions),
fix them and re-run "mstone setup" until everything works.
Install test accounts:
Setup will create a file called conf/MAILHOST.ldif (where MAILHOST is the
name of your mail server). If you are not using Netscape Messaging
and Directory Servers, then you may have to edit the ldif file or use
alternate means to create the user accounts.
To import these users into Netscape Messaging Server, use "add
entries" from the directory console or use the ldapmodify command line
utility.
Note: imports will go faster if access logging is disabled. For large
user counts (more than 10,000 users), it may be much faster to export
the current database, merge the files together manually, and then
import the new database.
Here is how the ldapmodify supplied with Netscape Messaging Server
would be used.
setenv LD_LIBRARY_PATH /usr/netscape/messaging/lib
cd /usr/netscape/messaging
shared/bin/ldapmodify -h mailhost -a -D 'cn=directory manager' -w d_m_password < conf/MAILHOST.ldif
Check time consistency:
IMPORTANT: The system time on each client machine must be synchronized
within one second of each other for accurate results graphs.
Run "checktime" to see the time on each client. There should not be
more than two seconds difference among the displayed time.
The best way to synchronize clients is use NTP (Network Time Protocol)
or similar protocols (like rdate or timeslave) that have sub second
accuracy.
A simple utility called "timesync" is provide to push the local
system time to all clients. You must be root and have root rsh
permissions to use timesync. Timesync only works on OSs that support
setting seconds using "date MMDDhhmmCCYY.ss". Timesync is only
accurate to a second (at best) and should only be used if better
protocols aren't available.
When running the test master on NT, "checktime" and "timesync" are
never needed (because there is only one client machine). Timesync
will be ignored for NT clients, another method must be used
(e.g. timeserv or Dimension4).
Run tests:
Try it out. Use small process and thread counts until everything is
working.
mstone pop -t 30s
The script will tell you how many processes and threads it is running
on each system and where errors are logged. At the end of the test,
it will print out a URL for the test results and an indication of the
size of the errorlog file (stderr).
The results of the mstone run will display statistics for each
protocol that was tested. The results are presented in both a HTML
web page and a text file. The text file is simple and uniform, while
the web page is more user readable. The web page has links to the
test configuration files, error log, and the text version.
For long tests run (e.g. 8 hours), the results can be updated while
the test is running by using the "process" utility. Don't run
"process" near the very end of the test.
If a test has to be aborted, then use "process" to generate a report
using the available data.
Customize tests:
Copy and edit the scripts (e.g. "conf/pop.wld") to define new tests.
The CONFIG section specifies all the attributes used in the test.
Other sections specify the protocols to be tested and the parameters
for them.
All switches can be overridden on the command line to facilitate
easier testing. The exact configuration (include command line
overrides) is stored with the results from each test.
Maintenance:
You can run "mstone setup" at any time (except during a test :-) to
update the files on the client machines.
Use "mstone cleanup" to remove the files created by "mstone setup".
After the test is finished, the directories under "tmp/" can be
compressed or deleted to save space. All the information about a test
run is stored in the "results/" directories.
Configuring client machines:
Edit conf/general.wld to include CLIENT sections for each machines to
use.
You can also specify the OS type for each client machine. Set the
"Arch" parameter in each CLIENT section as appropriate (e.g. SunOS5.6,
Linux2.2_x86, AIX4.2, HP-UXB.11.00, IRIX6.5, OSF1V4.0, WINNT4.0). The
directories under "bin" specify the available OS types.
For NT4.0 clients with a UNIX test master, you will need to configure
"command" and "tempDir" for proper operation. See the "HOSTS=winnt01"
example in conf/sample.wld.
The total number of processes and threads that can be supported on a
client is dependent on the number of commands in the test, the OS, and
available memory. Check the stderr log for messages about not being
able to create processes or threads. Check on the client machines
during the test and make sure they aren't running out of CPU. The
UNIX programs "top" and "vmstat" are good for this. If the client CPU
is more than 75% busy, use more machines.
Also watch out for network saturation. You may have to use machines
with separate networks to the server to reach full server load.
Know problems:
There can be extraneous errors or connections after the specified end
of the test. These are most likely do to stopping the test and should
be ignored.
At the end of the test, all current connections will logout without
any delays. This can cause very high peak loads.
If one process exits early (due to misconfiguration or resource
exhaustion) and the monitoring command did not specify a count (%c),
then the monitoring tasks will be terminated early as well.
Monitoring commands that specify a count (%c), may take longer than
predicted and delay the processing of test results. This is because
vmstat actually delays the requested time plus the time needed to
generate the statistics summary.
If you are doing tests with large thread counts, you may have to run
as root to allow mailclient to raise its resource limits.
The telemetry logging for SMTP, POP3, and IMAP4 is incomplete. Most
commands are captured, but banners and message contents may be missing.
The MaxBlocks parameter gets divided by the total number of processes
before starting each client. This doesn't account for clients that
don't have commands to run.
The HTTP protocol used by WMAP allows connections to be dropped and
re-connected as needed. WMAP logs this as an error and an additional
connect. The error log must be consulted to distinguish another types
of connection errors (timeout or connection refused) from an automatic
re-connect.
The HTTP protocol test is experimental and subject to change.

View File

@@ -1,19 +0,0 @@
The contents of this software package are subject to the Netscape
Public License Version 1.1 (the "License"); you may not use this
software 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.
Alternatively, the this software package may be used under the terms
of the GNU Public License (the "GPL"), in which case the provisions of
the GPL are applicable instead of those above. If you wish to allow
use of your version of this file only under the terms of the GPL and
not to allow others to use your version of this file under the NPL,
indicate your decision by deleting the provisions above and replace
them with the notice and other provisions required by the GPL. If you
do not delete the provisions above, a recipient may use your version
of this file under either the NPL or the GPL.

View File

@@ -1,535 +0,0 @@
MOZILLA PUBLIC LICENSE
Version 1.1
---------------
1. Definitions.
1.0.1. "Commercial Use" means distribution or otherwise making the
Covered Code available to a third party.
1.1. "Contributor" means each entity that creates or contributes to
the creation of Modifications.
1.2. "Contributor Version" means the combination of the Original
Code, prior Modifications used by a Contributor, and the Modifications
made by that particular Contributor.
1.3. "Covered Code" means the Original Code or Modifications or the
combination of the Original Code and Modifications, in each case
including portions thereof.
1.4. "Electronic Distribution Mechanism" means a mechanism generally
accepted in the software development community for the electronic
transfer of data.
1.5. "Executable" means Covered Code in any form other than Source
Code.
1.6. "Initial Developer" means the individual or entity identified
as the Initial Developer in the Source Code notice required by Exhibit
A.
1.7. "Larger Work" means a work which combines Covered Code or
portions thereof with code not governed by the terms of this License.
1.8. "License" means this document.
1.8.1. "Licensable" means having the right to grant, to the maximum
extent possible, whether at the time of the initial grant or
subsequently acquired, any and all of the rights conveyed herein.
1.9. "Modifications" means any addition to or deletion from the
substance or structure of either the Original Code or any previous
Modifications. When Covered Code is released as a series of files, a
Modification is:
A. Any addition to or deletion from the contents of a file
containing Original Code or previous Modifications.
B. Any new file that contains any part of the Original Code or
previous Modifications.
1.10. "Original Code" means Source Code of computer software code
which is described in the Source Code notice required by Exhibit A as
Original Code, and which, at the time of its release under this
License is not already Covered Code governed by this License.
1.10.1. "Patent Claims" means any patent claim(s), now owned or
hereafter acquired, including without limitation, method, process,
and apparatus claims, in any patent Licensable by grantor.
1.11. "Source Code" means the preferred form of the Covered Code for
making modifications to it, including all modules it contains, plus
any associated interface definition files, scripts used to control
compilation and installation of an Executable, or source code
differential comparisons against either the Original Code or another
well known, available Covered Code of the Contributor's choice. The
Source Code can be in a compressed or archival form, provided the
appropriate decompression or de-archiving software is widely available
for no charge.
1.12. "You" (or "Your") means an individual or a legal entity
exercising rights under, and complying with all of the terms of, this
License or a future version of this License issued under Section 6.1.
For legal entities, "You" includes any entity which controls, is
controlled by, or is under common control with You. For purposes of
this definition, "control" means (a) the power, direct or indirect,
to cause the direction or management of such entity, whether by
contract or otherwise, or (b) ownership of more than fifty percent
(50%) of the outstanding shares or beneficial ownership of such
entity.
2. Source Code License.
2.1. The Initial Developer Grant.
The Initial Developer hereby grants You a world-wide, royalty-free,
non-exclusive license, subject to third party intellectual property
claims:
(a) under intellectual property rights (other than patent or
trademark) Licensable by Initial Developer to use, reproduce,
modify, display, perform, sublicense and distribute the Original
Code (or portions thereof) with or without Modifications, and/or
as part of a Larger Work; and
(b) under Patents Claims infringed by the making, using or
selling of Original Code, to make, have made, use, practice,
sell, and offer for sale, and/or otherwise dispose of the
Original Code (or portions thereof).
(c) the licenses granted in this Section 2.1(a) and (b) are
effective on the date Initial Developer first distributes
Original Code under the terms of this License.
(d) Notwithstanding Section 2.1(b) above, no patent license is
granted: 1) for code that You delete from the Original Code; 2)
separate from the Original Code; or 3) for infringements caused
by: i) the modification of the Original Code or ii) the
combination of the Original Code with other software or devices.
2.2. Contributor Grant.
Subject to third party intellectual property claims, each Contributor
hereby grants You a world-wide, royalty-free, non-exclusive license
(a) under intellectual property rights (other than patent or
trademark) Licensable by Contributor, to use, reproduce, modify,
display, perform, sublicense and distribute the Modifications
created by such Contributor (or portions thereof) either on an
unmodified basis, with other Modifications, as Covered Code
and/or as part of a Larger Work; and
(b) under Patent Claims infringed by the making, using, or
selling of Modifications made by that Contributor either alone
and/or in combination with its Contributor Version (or portions
of such combination), to make, use, sell, offer for sale, have
made, and/or otherwise dispose of: 1) Modifications made by that
Contributor (or portions thereof); and 2) the combination of
Modifications made by that Contributor with its Contributor
Version (or portions of such combination).
(c) the licenses granted in Sections 2.2(a) and 2.2(b) are
effective on the date Contributor first makes Commercial Use of
the Covered Code.
(d) Notwithstanding Section 2.2(b) above, no patent license is
granted: 1) for any code that Contributor has deleted from the
Contributor Version; 2) separate from the Contributor Version;
3) for infringements caused by: i) third party modifications of
Contributor Version or ii) the combination of Modifications made
by that Contributor with other software (except as part of the
Contributor Version) or other devices; or 4) under Patent Claims
infringed by Covered Code in the absence of Modifications made by
that Contributor.
3. Distribution Obligations.
3.1. Application of License.
The Modifications which You create or to which You contribute are
governed by the terms of this License, including without limitation
Section 2.2. The Source Code version of Covered Code may be
distributed only under the terms of this License or a future version
of this License released under Section 6.1, and You must include a
copy of this License with every copy of the Source Code You
distribute. You may not offer or impose any terms on any Source Code
version that alters or restricts the applicable version of this
License or the recipients' rights hereunder. However, You may include
an additional document offering the additional rights described in
Section 3.5.
3.2. Availability of Source Code.
Any Modification which You create or to which You contribute must be
made available in Source Code form under the terms of this License
either on the same media as an Executable version or via an accepted
Electronic Distribution Mechanism to anyone to whom you made an
Executable version available; and if made available via Electronic
Distribution Mechanism, must remain available for at least twelve (12)
months after the date it initially became available, or at least six
(6) months after a subsequent version of that particular Modification
has been made available to such recipients. You are responsible for
ensuring that the Source Code version remains available even if the
Electronic Distribution Mechanism is maintained by a third party.
3.3. Description of Modifications.
You must cause all Covered Code to which You contribute to contain a
file documenting the changes You made to create that Covered Code and
the date of any change. You must include a prominent statement that
the Modification is derived, directly or indirectly, from Original
Code provided by the Initial Developer and including the name of the
Initial Developer in (a) the Source Code, and (b) in any notice in an
Executable version or related documentation in which You describe the
origin or ownership of the Covered Code.
3.4. Intellectual Property Matters
(a) Third Party Claims.
If Contributor has knowledge that a license under a third party's
intellectual property rights is required to exercise the rights
granted by such Contributor under Sections 2.1 or 2.2,
Contributor must include a text file with the Source Code
distribution titled "LEGAL" which describes the claim and the
party making the claim in sufficient detail that a recipient will
know whom to contact. If Contributor obtains such knowledge after
the Modification is made available as described in Section 3.2,
Contributor shall promptly modify the LEGAL file in all copies
Contributor makes available thereafter and shall take other steps
(such as notifying appropriate mailing lists or newsgroups)
reasonably calculated to inform those who received the Covered
Code that new knowledge has been obtained.
(b) Contributor APIs.
If Contributor's Modifications include an application programming
interface and Contributor has knowledge of patent licenses which
are reasonably necessary to implement that API, Contributor must
also include this information in the LEGAL file.
(c) Representations.
Contributor represents that, except as disclosed pursuant to
Section 3.4(a) above, Contributor believes that Contributor's
Modifications are Contributor's original creation(s) and/or
Contributor has sufficient rights to grant the rights conveyed by
this License.
3.5. Required Notices.
You must duplicate the notice in Exhibit A in each file of the Source
Code. If it is not possible to put such notice in a particular Source
Code file due to its structure, then You must include such notice in a
location (such as a relevant directory) where a user would be likely
to look for such a notice. If You created one or more Modification(s)
You may add your name as a Contributor to the notice described in
Exhibit A. You must also duplicate this License in any documentation
for the Source Code where You describe recipients' rights or ownership
rights relating to Covered Code. You may choose to offer, and to
charge a fee for, warranty, support, indemnity or liability
obligations to one or more recipients of Covered Code. However, You
may do so only on Your own behalf, and not on behalf of the Initial
Developer or any Contributor. You must make it absolutely clear than
any such warranty, support, indemnity or liability obligation is
offered by You alone, and You hereby agree to indemnify the Initial
Developer and every Contributor for any liability incurred by the
Initial Developer or such Contributor as a result of warranty,
support, indemnity or liability terms You offer.
3.6. Distribution of Executable Versions.
You may distribute Covered Code in Executable form only if the
requirements of Section 3.1-3.5 have been met for that Covered Code,
and if You include a notice stating that the Source Code version of
the Covered Code is available under the terms of this License,
including a description of how and where You have fulfilled the
obligations of Section 3.2. The notice must be conspicuously included
in any notice in an Executable version, related documentation or
collateral in which You describe recipients' rights relating to the
Covered Code. You may distribute the Executable version of Covered
Code or ownership rights under a license of Your choice, which may
contain terms different from this License, provided that You are in
compliance with the terms of this License and that the license for the
Executable version does not attempt to limit or alter the recipient's
rights in the Source Code version from the rights set forth in this
License. If You distribute the Executable version under a different
license You must make it absolutely clear that any terms which differ
from this License are offered by You alone, not by the Initial
Developer or any Contributor. You hereby agree to indemnify the
Initial Developer and every Contributor for any liability incurred by
the Initial Developer or such Contributor as a result of any such
terms You offer.
3.7. Larger Works.
You may create a Larger Work by combining Covered Code with other code
not governed by the terms of this License and distribute the Larger
Work as a single product. In such a case, You must make sure the
requirements of this License are fulfilled for the Covered Code.
4. Inability to Comply Due to Statute or Regulation.
If it is impossible for You to comply with any of the terms of this
License with respect to some or all of the Covered Code due to
statute, judicial order, or regulation then You must: (a) comply with
the terms of this License to the maximum extent possible; and (b)
describe the limitations and the code they affect. Such description
must be included in the LEGAL file described in Section 3.4 and must
be included with all distributions of the Source Code. Except to the
extent prohibited by statute or regulation, such description must be
sufficiently detailed for a recipient of ordinary skill to be able to
understand it.
5. Application of this License.
This License applies to code to which the Initial Developer has
attached the notice in Exhibit A and to related Covered Code.
6. Versions of the License.
6.1. New Versions.
Netscape Communications Corporation ("Netscape") may publish revised
and/or new versions of the License from time to time. Each version
will be given a distinguishing version number.
6.2. Effect of New Versions.
Once Covered Code has been published under a particular version of the
License, You may always continue to use it under the terms of that
version. You may also choose to use such Covered Code under the terms
of any subsequent version of the License published by Netscape. No one
other than Netscape has the right to modify the terms applicable to
Covered Code created under this License.
6.3. Derivative Works.
If You create or use a modified version of this License (which you may
only do in order to apply it to code which is not already Covered Code
governed by this License), You must (a) rename Your license so that
the phrases "Mozilla", "MOZILLAPL", "MOZPL", "Netscape",
"MPL", "NPL" or any confusingly similar phrase do not appear in your
license (except to note that your license differs from this License)
and (b) otherwise make it clear that Your version of the license
contains terms which differ from the Mozilla Public License and
Netscape Public License. (Filling in the name of the Initial
Developer, Original Code or Contributor in the notice described in
Exhibit A shall not of themselves be deemed to be modifications of
this License.)
7. DISCLAIMER OF WARRANTY.
COVERED CODE IS PROVIDED UNDER THIS LICENSE ON AN "AS IS" BASIS,
WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING,
WITHOUT LIMITATION, WARRANTIES THAT THE COVERED CODE IS FREE OF
DEFECTS, MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE OR NON-INFRINGING.
THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE COVERED CODE
IS WITH YOU. SHOULD ANY COVERED CODE PROVE DEFECTIVE IN ANY RESPECT,
YOU (NOT THE INITIAL DEVELOPER OR ANY OTHER CONTRIBUTOR) ASSUME THE
COST OF ANY NECESSARY SERVICING, REPAIR OR CORRECTION. THIS DISCLAIMER
OF WARRANTY CONSTITUTES AN ESSENTIAL PART OF THIS LICENSE. NO USE OF
ANY COVERED CODE IS AUTHORIZED HEREUNDER EXCEPT UNDER THIS DISCLAIMER.
8. TERMINATION.
8.1. This License and the rights granted hereunder will terminate
automatically if You fail to comply with terms herein and fail to cure
such breach within 30 days of becoming aware of the breach. All
sublicenses to the Covered Code which are properly granted shall
survive any termination of this License. Provisions which, by their
nature, must remain in effect beyond the termination of this License
shall survive.
8.2. If You initiate litigation by asserting a patent infringement
claim (excluding declatory judgment actions) against Initial Developer
or a Contributor (the Initial Developer or Contributor against whom
You file such action is referred to as "Participant") alleging that:
(a) such Participant's Contributor Version directly or indirectly
infringes any patent, then any and all rights granted by such
Participant to You under Sections 2.1 and/or 2.2 of this License
shall, upon 60 days notice from Participant terminate prospectively,
unless if within 60 days after receipt of notice You either: (i)
agree in writing to pay Participant a mutually agreeable reasonable
royalty for Your past and future use of Modifications made by such
Participant, or (ii) withdraw Your litigation claim with respect to
the Contributor Version against such Participant. If within 60 days
of notice, a reasonable royalty and payment arrangement are not
mutually agreed upon in writing by the parties or the litigation claim
is not withdrawn, the rights granted by Participant to You under
Sections 2.1 and/or 2.2 automatically terminate at the expiration of
the 60 day notice period specified above.
(b) any software, hardware, or device, other than such Participant's
Contributor Version, directly or indirectly infringes any patent, then
any rights granted to You by such Participant under Sections 2.1(b)
and 2.2(b) are revoked effective as of the date You first made, used,
sold, distributed, or had made, Modifications made by that
Participant.
8.3. If You assert a patent infringement claim against Participant
alleging that such Participant's Contributor Version directly or
indirectly infringes any patent where such claim is resolved (such as
by license or settlement) prior to the initiation of patent
infringement litigation, then the reasonable value of the licenses
granted by such Participant under Sections 2.1 or 2.2 shall be taken
into account in determining the amount or value of any payment or
license.
8.4. In the event of termination under Sections 8.1 or 8.2 above,
all end user license agreements (excluding distributors and resellers)
which have been validly granted by You or any distributor hereunder
prior to termination shall survive termination.
9. LIMITATION OF LIABILITY.
UNDER NO CIRCUMSTANCES AND UNDER NO LEGAL THEORY, WHETHER TORT
(INCLUDING NEGLIGENCE), CONTRACT, OR OTHERWISE, SHALL YOU, THE INITIAL
DEVELOPER, ANY OTHER CONTRIBUTOR, OR ANY DISTRIBUTOR OF COVERED CODE,
OR ANY SUPPLIER OF ANY OF SUCH PARTIES, BE LIABLE TO ANY PERSON FOR
ANY INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES OF ANY
CHARACTER INCLUDING, WITHOUT LIMITATION, DAMAGES FOR LOSS OF GOODWILL,
WORK STOPPAGE, COMPUTER FAILURE OR MALFUNCTION, OR ANY AND ALL OTHER
COMMERCIAL DAMAGES OR LOSSES, EVEN IF SUCH PARTY SHALL HAVE BEEN
INFORMED OF THE POSSIBILITY OF SUCH DAMAGES. THIS LIMITATION OF
LIABILITY SHALL NOT APPLY TO LIABILITY FOR DEATH OR PERSONAL INJURY
RESULTING FROM SUCH PARTY'S NEGLIGENCE TO THE EXTENT APPLICABLE LAW
PROHIBITS SUCH LIMITATION. SOME JURISDICTIONS DO NOT ALLOW THE
EXCLUSION OR LIMITATION OF INCIDENTAL OR CONSEQUENTIAL DAMAGES, SO
THIS EXCLUSION AND LIMITATION MAY NOT APPLY TO YOU.
10. U.S. GOVERNMENT END USERS.
The Covered Code is a "commercial item," as that term is defined in
48 C.F.R. 2.101 (Oct. 1995), consisting of "commercial computer
software" and "commercial computer software documentation," as such
terms are used in 48 C.F.R. 12.212 (Sept. 1995). Consistent with 48
C.F.R. 12.212 and 48 C.F.R. 227.7202-1 through 227.7202-4 (June 1995),
all U.S. Government End Users acquire Covered Code with only those
rights set forth herein.
11. MISCELLANEOUS.
This License represents the complete agreement concerning subject
matter hereof. If any provision of this License is held to be
unenforceable, such provision shall be reformed only to the extent
necessary to make it enforceable. This License shall be governed by
California law provisions (except to the extent applicable law, if
any, provides otherwise), excluding its conflict-of-law provisions.
With respect to disputes in which at least one party is a citizen of,
or an entity chartered or registered to do business in the United
States of America, any litigation relating to this License shall be
subject to the jurisdiction of the Federal Courts of the Northern
District of California, with venue lying in Santa Clara County,
California, with the losing party responsible for costs, including
without limitation, court costs and reasonable attorneys' fees and
expenses. The application of the United Nations Convention on
Contracts for the International Sale of Goods is expressly excluded.
Any law or regulation which provides that the language of a contract
shall be construed against the drafter shall not apply to this
License.
12. RESPONSIBILITY FOR CLAIMS.
As between Initial Developer and the Contributors, each party is
responsible for claims and damages arising, directly or indirectly,
out of its utilization of rights under this License and You agree to
work with Initial Developer and Contributors to distribute such
responsibility on an equitable basis. Nothing herein is intended or
shall be deemed to constitute any admission of liability.
13. MULTIPLE-LICENSED CODE.
Initial Developer may designate portions of the Covered Code as
"Multiple-Licensed". "Multiple-Licensed" means that the Initial
Developer permits you to utilize portions of the Covered Code under
Your choice of the NPL or the alternative licenses, if any, specified
by the Initial Developer in the file described in Exhibit A.
EXHIBIT A-Netscape Public License.
"The contents of this file are subject to the Netscape Public
License Version 1.1 (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 the Netscape Mailstone code, released
March 17, 2000.
The Initial Developer of the Original Code is Netscape
Communications Corporation. Portions created by Netscape are
Copyright (C) 1999-2000 Netscape Communications Corporation. All
Rights Reserved.
Contributor(s): Dan Christian <robodan@netscape.com>
Marcel DePaolis <marcel@netscape.com>
Jim Salter <jsalter@netscape.com>
Mike Blakely, David Shak, Brain Williams
Alternatively, the contents of this file may be used under the
terms of the GNU General Public license Version 2 or later
(the "GPL"), in which case the provisions of GPL are
applicable instead of those above. If you wish to allow use
of your version of this file only under the terms of the GPL
and not to allow others to use your version of this file
under the NPL, indicate your decision by deleting the
provisions above and replace them with the notice and other
provisions required by the GPL. If you do not delete the
provisions above, a recipient may use your version of this
file under either the NPL or the GPL License."
----------------------------------------------------------------------
AMENDMENTS
The Netscape Public License Version 1.1 ("NPL") consists of the
Mozilla Public License Version 1.1 with the following Amendments,
including Exhibit A-Netscape Public License. Files identified with
"Exhibit A-Netscape Public License" are governed by the Netscape
Public License Version 1.1.
Additional Terms applicable to the Netscape Public License.
I. Effect.
These additional terms described in this Netscape Public
License -- Amendments shall apply to the Mozilla Communicator
client code and to all Covered Code under this License.
II. "Netscape's Branded Code" means Covered Code that Netscape
distributes and/or permits others to distribute under one or more
trademark(s) which are controlled by Netscape but which are not
licensed for use under this License.
III. Netscape and logo.
This License does not grant any rights to use the trademarks
"Netscape", the "Netscape N and horizon" logo or the "Netscape
lighthouse" logo, "Netcenter", "Gecko", "Java" or "JavaScript",
"Smart Browsing" even if such marks are included in the Original
Code or Modifications.
IV. Inability to Comply Due to Contractual Obligation.
Prior to licensing the Original Code under this License, Netscape
has licensed third party code for use in Netscape's Branded Code.
To the extent that Netscape is limited contractually from making
such third party code available under this License, Netscape may
choose to reintegrate such code into Covered Code without being
required to distribute such code in Source Code form, even if
such code would otherwise be considered "Modifications" under
this License.
V. Use of Modifications and Covered Code by Initial Developer.
V.1. In General.
The obligations of Section 3 apply to Netscape, except to
the extent specified in this Amendment, Section V.2 and V.3.
V.2. Other Products.
Netscape may include Covered Code in products other than the
Netscape's Branded Code which are released by Netscape
during the two (2) years following the release date of the
Original Code, without such additional products becoming
subject to the terms of this License, and may license such
additional products on different terms from those contained
in this License.
V.3. Alternative Licensing.
Netscape may license the Source Code of Netscape's Branded
Code, including Modifications incorporated therein, without
such Netscape Branded Code becoming subject to the terms of
this License, and may license such Netscape Branded Code on
different terms from those contained in this License.
VI. Litigation.
Notwithstanding the limitations of Section 11 above, the
provisions regarding litigation in Section 11(a), (b) and (c) of
the License shall apply to all disputes relating to this License.

View File

@@ -1,246 +0,0 @@
# Makefile for mstone
# use gmake
# Builds each of the components and then packages everything
topsrcdir = .
CP := cp -p
ifndef INCLUDED_CONFIG_MK
include $(topsrcdir)/config/config.mk
endif
# dynamically find the optional directories names
LIBGD_DIR = $(wildcard gd?.*)
GNUPLOT_DIR = $(wildcard gnuplot-?.*)
PERL_DIR = $(wildcard perl5.*)
# file that we package
GDFILES = gd.txt gd.html libgd.* gd.h demoin.gif gddemo giftogd webgif
GNUPLOTFILES = gnuplot Copyright gnuplot_x11 gnuplot.1 gnuplot.gih
VERSION = 4.3
TARBALL = mstone-$(VERSION)-$(NSARCH)$(OBJDIR_TAG).tar.gz
ZIPFILE = mstone-$(VERSION)-$(NSARCH)$(OBJDIR_TAG).zip
TARBALL_ALL = mstone-$(VERSION)-all$(OBJDIR_TAG).tar.gz
ZIPFILE_ALL = mstone-$(VERSION)-all$(OBJDIR_TAG).zip
NTFILES = mstone.bat process.bat setup.bat
all:: usage
usage::
@$(ECHO) "gmake [ release | rpackage | debug | dpackage ]"
@$(ECHO) " [ DIST=/m/dist/mailstone/1999xxxx dist ]"
@$(ECHO) " [ all_DBG | all_OPT ]"
@$(ECHO) "perl is" $(PERL_DIR) ". gd is" $(LIBGD_DIR) ". gnuplot is" $(GNUPLOT_DIR) "."
targets:: $(OBJDIR) mailclient
ifneq (,$(LIBGD_DIR))
targets:: libgd
endif
ifneq (,$(GNUPLOT_DIR))
targets:: gnuplot
endif
ifneq (,$(PERL_DIR))
targets:: perl
endif
$(OBJDIR):
-mkdir -p $(OBJDIR)
mailclient::
@$(ECHO) "\n===== [`date`] making OS_CONFIG=$(NSARCH) BUILD_VARIANT=$(BUILD_VARIANT)\n"
cd src; $(MAKE) BUILD_VARIANT=$(BUILD_VARIANT) OBJDIR=../$(OBJDIR) PKGDIR=../$(PKGDIR) all
# Use our top level makefiles to drive the component builds
libgd $(OBJDIR)/gd/libgd.a::
$(MAKE) -f gd.mk LIBGD_DIR=$(LIBGD_DIR) libgd
gnuplot $(OBJDIR)/gnuplot/gnuplot::
$(MAKE) -f gnuplot.mk LIBGD_DIR=$(LIBGD_DIR) GNUPLOT_DIR=$(GNUPLOT_DIR) gnuplot
perl $(OBJDIR)/perl/perl::
$(MAKE) -f perl.mk PERL_DIR=$(PERL_DIR) perl
# Create packaging binary directories
# Note: dont make gd or gnuplot here. For multi-OS, they are links
mkpkgdirs:: $(PKGDIR)/bin $(PKGDIR)/conf $(PKGDIR)/data $(PKGDIR)/doc
$(PKGDIR)/bin:
mkdir -p $(PKGDIR)/bin
$(PKGDIR)/conf:
mkdir -p $(PKGDIR)/conf
$(PKGDIR)/data:
mkdir -p $(PKGDIR)/data
$(PKGDIR)/doc:
mkdir -p $(PKGDIR)/doc
$(PKGDIR)/gd:
mkdir -p $(PKGDIR)/gd
$(PKGDIR)/gnuplot:
mkdir -p $(PKGDIR)/gnuplot
$(PKGDIR)/perl:
mkdir -p $(PKGDIR)/perl
# operating system independent share-files (at least for Unix)
pkg-share-files:: mkpkgdirs
@$(ECHO) "\n===== [`date`] making package share-files...\n"
$(CP) mstone process $(PKGDIR)
(cd $(PKGDIR); [ ! -f setup ] || rm -f setup; ln -s mstone setup)
(cd $(PKGDIR); [ ! -f cleanup ] || rm -f cleanup; ln -s mstone cleanup)
(cd $(PKGDIR); [ ! -f checktime ] || rm -f checktime; ln -s mstone checktime)
(cd $(PKGDIR); [ ! -f timesync ] || rm -f timesync; ln -s mstone timesync)
$(CP) nsarch bin/*.pl $(PKGDIR)/bin
$(CP) conf/*.wld conf/*.wld.in conf/*.html $(PKGDIR)/conf
$(CP) data/*.msg $(PKGDIR)/data
$(CP) doc/*.html doc/*.gif $(PKGDIR)/doc
$(CP) INSTALL $(PKGDIR)
$(CP) README $(PKGDIR)
$(CP) ChangeLog $(PKGDIR)
$(CP) LICENSE $(PKGDIR)
# split out OS specific file so that combined packaging possible (set PKGDIR)
pkg-arch-files-gd:: $(PKGDIR)/gd $(OBJDIR)/gd/libgd.a
$(CP) $(addprefix $(OBJDIR)/gd/, $(GDFILES)) $(PKGDIR)/gd
-$(STRIP) $(PKGDIR)/gd/webgif $(PKGDIR)/gd/giftogd $(PKGDIR)/gd/gddemo
pkg-arch-files-gnuplot:: $(PKGDIR)/gnuplot $(OBJDIR)/gnuplot/gnuplot
$(CP) $(addprefix $(OBJDIR)/gnuplot/, $(GNUPLOTFILES)) $(PKGDIR)/gnuplot
-$(STRIP) $(PKGDIR)/gnuplot/gnuplot $(PKGDIR)/gnuplot/gnuplot_x11
ifneq (,$(LIBGD_DIR))
pkg-arch-files:: pkg-arch-files-gd
endif
ifneq (,$(GNUPLOT_DIR))
pkg-arch-files:: pkg-arch-files-gnuplot
endif
pkg-arch-files:: $(PKGDIR)/bin $(OBJDIR)/mailclient
@$(ECHO) "\n===== [`date`] making package arch-files...\n"
$(CP) $(OBJDIR)/mailclient $(PKGDIR)/bin
-$(STRIP) $(PKGDIR)/bin/mailclient
pkg-perl-files:: $(PKGDIR)/bin $(OBJDIR)/perl/perl
@$(ECHO) "\n===== [`date`] making package perl-files...\n"
$(MAKE) -f perl.mk PERL_DIR=$(PERL_DIR) \
BUILD_VARIANT=$(BUILD_VARIANT) \
OBJDIR=$(OBJDIR) PKGDIR=$(PKGDIR) package-perl
find $(PKGDIR)/perl/lib -name .packlist -exec rm {} \; -print
-$(STRIP) $(PKGDIR)/perl/bin/perl
-$(STRIP) $(PKGDIR)/perl/bin/a2p
# for combined packaging, this should not be part of pkg-arch-files
# perl is handled seperately do to its size
ifneq (,$(PERL_DIR))
pkg:: pkg-perl-files
endif
pkg:: targets pkg-share-files pkg-arch-files
tarball: build/$(TARBALL)
build/$(TARBALL):
@$(ECHO) "\n===== [`date`] making os tar file...\n"
-rm -f build/$(TARBALL)
cd $(dir $(PKGDIR)) && tar cf - . | gzip > ../../$(TARBALL)
zipfile: build/$(ZIPFILE)
build/$(ZIPFILE):
@$(ECHO) "\n===== [`date`] making os zip file...\n"
-rm -f build/$(ZIPFILE)
cd $(dir $(PKGDIR)) && zip -r -q ../../$(ZIPFILE) .
########################################################################
# Generate a combined build for every Unix OS that is already packaged
# NT has to be done seperately because it has different file names
# We have to nuke some old parts, because permissions wont allow overwrites
# Finally, dont ship perl development headers and libraries
all_DBG all_OPT::
@$(ECHO) "===== [`date`] unified packaging for $@..."
$(MAKE) NSARCH=$@ OBJDIR_TAG='' \
PKGDIR=$(topsrcdir)/build/package/$@.OBJ/mstone pkg-share-files
./ospkg.sh $@.OBJ \
$(notdir $(shell ls -d build/package/[A-Z]*$(subst all,,$@.OBJ)))
[ -d $(topsrcdir)/build/package/$@.OBJ/mstone/bin/WINNT4.0 ] \
&& cp -p $(NTFILES) $(topsrcdir)/build/package/$@.OBJ/mstone; :
-rm -f ./build/mstone-$(VERSION)-$@.tar.gz
cd ./build/package/$@.OBJ \
&& tar cf - . | gzip > ../../mstone-$(VERSION)-$@.tar.gz
-rm -f ./build/mstone-$(VERSION)-$@.zip
cd ./build/package/$@.OBJ \
&& zip -r -q ../../mstone-$(VERSION)-$@.zip .
########################################################################
# Copy all the packaged trees to the distribution site
# Copy in the unified tarball and zip file
# Link mstone to mailstone for Netscape back compatibility
# Re-map short Linux name to standard Netscape convention
dist::
@[ "$(DIST)" != "" ] || ($(MAKE) usage && /bin/false)
@[ ! -d "$(DIST)" ] || ($(ECHO) "Error: $(DIST) already exists" && \
$(MAKE) usage && /bin/false)
mkdir -p $(DIST)
cp -p build/mstone-$(VERSION)-all_*.*[a-z] $(DIST)/
(cd build/package; tar cf - *.OBJ) | (cd $(DIST); tar xf - )
for l in $(DIST)/*_???.OBJ ; do \
(cd $$l; ln -s mstone mailstone); done
cd $(DIST); for l in Linux*_???.OBJ ; do \
nn=`echo $$l | sed -e 's/_OPT/_glibc_PTH_OPT/' | sed -e 's/_DBG/_glibc_PTH_DBG/'`; \
ln -s $$l $$nn; done
# since the default is release mode, this can just work off a dependency
release:: targets
#release::
# @$(ECHO) "\n===== [`date`] making release build..."
# $(MAKE) BUILD_VARIANT=release OBJDIR_TAG=_OPT targets
@$(ECHO) "\n===== [`date`] making release build done."
rpackage:: release pkg #tarball zipfile
#rpackage:: release
# @$(ECHO) "\n===== [`date`] making release package..."
# $(MAKE) BUILD_VARIANT=release OBJDIR_TAG=_OPT pkg tarball zipfile
@$(ECHO) "\n===== [`date`] making release package done."
# since the default is release mode, start a make with the right mode
debug::
@$(ECHO) "\n===== [`date`] making debug build..."
$(MAKE) BUILD_VARIANT=debug OBJDIR_TAG=_DBG targets
@$(ECHO) "\n===== [`date`] making debug build done."
# We dont usually bother to tar up a debug build
dpackage:: debug
@$(ECHO) "\n===== [`date`] making debug package..."
$(MAKE) BUILD_VARIANT=debug OBJDIR_TAG=_DBG pkg
@$(ECHO) "\n===== [`date`] making debug package done."
# These are old and may be broken
cleanvariant::
(cd src; $(MAKE) OBJDIR=../$(OBJDIR) clean)
rm -rf $(PKGDIR)
clean::
$(MAKE) BUILD_VARIANT=release OBJDIR_TAG=_OPT cleanvariant
$(MAKE) BUILD_VARIANT=debug OBJDIR_TAG=_DBG cleanvariant
distcleanvariant::
(cd src; $(MAKE) OBJDIR=../$(OBJDIR) distclean)
rm -rf $(OBJDIR) $(PKGDIR)
distclean:: clean
$(MAKE) BUILD_VARIANT=release OBJDIR_TAG=_OPT distcleanvariant
$(MAKE) BUILD_VARIANT=debug OBJDIR_TAG=_DBG distcleanvariant

View File

@@ -1,76 +0,0 @@
MSTONE 4.2
Mstone is a mail server performance testing tool designed to simulate
the different types and volume of mail traffic a mail server would
experience during a peak activity period. Mstone was formerly known
as Mailstone.
A quick installation guide is available in INSTALL.
The full Mailstone 4.15 user manual is available at
http://developer.iplanet.com/docs/manuals/messaging.html
Testing strategy
----------------
Mstone is capable of opening SMTP, POP3, IMAP4, and other protocol
connections to mail servers. The number and type of connections made
to the mail server is based on a weighted command list which provides
the ability to test mail server implementation requirements.
A series of perl script allow you to setup client machines, run tests,
and then cleanup client machine files. Each client machine has a copy
of the mailclient program and SMTP message files. When the test is
run, the mailclient is started with the proper command line and work load.
After experimenting with mstone loads, you will notice that there
are a few factors that can distort server the byte and message
throughput. You will find that the server byte throughput is related
to the average SMTP message (file) size. Also, server throughput, in
bytes and messages, is affected by larger than normal POP3/IMAP4
mailboxes. So it is important to approach the mstone command
configuration with data collected from existing mail server
implementations, for example, a customer might say "during our peak
activity in the morning, we handle up to two thousand employees
sending an average of 5 messages of 20K average size and receiving 25
messages of same size". With input like this, you can begin tuning
mstone to generate relevant data.
There are two important things to consider when reviewing the results of
mstone performance analysis: Was the test run on target for
simulating the type and volume of mail traffic; and did the server, both
software and machine, handle the load within an acceptable margin?
With this information, it can be determined: whether enough SMTP
connections were made to the server during the run, and how many
messages were downloaded over how many POP3/IMAP4 connections. If the
number of SMTP connections is not in the acceptable range, then
consider adding more client processes/machines or checking the server
performance during the run. The message/connection ratio for
POP3/IMAP4 should be checked for soundness, and adjustments should be
made to the mailboxes before running the next test.
Monitoring the server performance during test runs is crucial in
understanding the results. If the number of client connections is not
being achieved and the server cpu usage and process run queue is not
settling down after the initial spike, then modifications to the server
architecture could be in order.
The analysis of mstone results is an iterative process of client
(mstone client) and server tuning. The bottom line is to determine
whether the messaging solution can handle the type of load expected in
an acceptable manner.
Server Log Tuning
-----------------
The Messaging and Directory server ship with access logging enabled by
default. This gives the most information about what is going on in
the system, but can reduce performance. You should test the way the
system will be run.
Noticeable performance increases are often obtained by disabling access
logging on the directory server and by reducing the logging level of
the messaging servers from "Notice" to "Warning".

View File

@@ -1,189 +0,0 @@
Mstone TODO List
Updated:
3-20-2000 Dan Christian
======================================================================
Minor improvements
Data reduction at each testbed client
Test message generator (plain and MIME styles)
More graphs for multiple runs
Option to drop a fraction of connections
IMAP delete without reading
Just get the message list and delete everything. This could
be the fastest way to drain out the store.
Display MIN/MAX or standard deviation on graphs
Gnuplot can do data points with error bars. You could either
use MIN/MAX or the standard deviation for the error bars. There are
issues with calculating the standard deviation numbers throughout the
graph that need to be addressed.
Statistics reset
At least the MIN and MAX statistics could be easily reset
during the test (after ramp up). This keeps the transients during
startup and shutdown from dominating these numbers. The standard
deviation statistics are much trickier to reset during the run. It
may be better to isolate sections in post processing.
Perl web server
Sometimes it would be nice to include our own web server to
provide the results (instead of using file: URLs). This would also be
a gateway to form based test configuration editing and allow results
to be interactively updated during tests. Perl with a socket library
could handle this without too much trouble.
Dynamic test loading
Finalize an API for dynamically loading tests. This would
allow tests to be added or updated separately from the core
functionality. This may be needed for some types of security testing.
Link graphs to the results tables
There are already tags by each graph. You should be able to
link the appropriate results table entry to each graph. This sort of
tricky since graphs often combine multiple entries.
Show statistics for every block
Statistics are actually kept for every block in every thread.
There should be a way to view information at this detail.
Man pages
The online docs are nice, but good 'ol man pages would be
great in a different way.
Reduce namespace polution
Scripts names like setup and cleanup are too general. They
should be part of the main 'mstone' script (e.g. mstone setup).
Examples of script series
Include example scripts to run entire series of tests in a
sane way.
Fix FORMAT clash
At the start of a test, each client process outputs the
information needed to report all its protocols. When there are
multiple processes on one client, these FORMAT lines can intermix and
cause parsing errors.
Set connection drop rate
Drop some percentage of the connections without a proper
shutdown. This tests how well a server can detect and recover from
hard disconnects.
Improve randomness
The way that we generate random numbers in a range may be not
generate the proper randomness. We are using lrand48()%range we
should use (lrand48/RAND_RANGE)*range. There are some end conditions
that need to be thought about. All of this is in the sequence code;
one change should fix (or break :) everything.
Also, we may be generating numbers that are never used. This
may be costly, and can create holes in the proper sequence.
Improve printing
The color graphs are great on screen, but tend to print
poorly. Either we need a better way to generate a printable version
(maybe through a CGI button), or the seperate protocols need to be
printed individually. Also, Communicator does a lousy job of keeping
title with tables or graphs. Hopefully, Mozilla will do better.
======================================================================
Whole new protocol tests:
ICQ
Test high volume instant messaging. Very useful for the
bridges and gateways that people are considering using.
WAP
WAP is the emerging standard for mobile phones.
WCAP
Web based calendar services
LDAP
Use the LDAP SDK to do basic LDAP testing. The SDK probably
isn't fast enough to call this a real performance test, but you can at
least test performance degredation due to load from a real application
(like a mail server).
DNS
Mail servers use DNS a lot. You should at least be able to
see if performance is degrading due to load.
Disk/filesystem
Test read, write, sync, link, un-link, and append performance under
multiple threads.
Cert servers
Test certificate authenticity checking performance
======================================================================
Possible dummy servers:
SMTP
Receive mail via SMTP and ignore it. Usefull for SMTP relay
testing.
DNS
Simulate slow DNS server lookups. Usefull for SMTP relay testing.
======================================================================
Major changes
Throttling
Monitor and control transaction rates so that specific load
levels can be easily specified. The rates should be able to vary to
simulate peek hour usage and disconnect-restore.
NSPR threading
Use NSPR for threading and sockets. This may allow other OSes
to be used as clients. This might be easy, since mstone does not need
any locking, just simple thread creation and harvesting. NSPR
argument parsing and hashes may also be useful.
SSL
Support SSL on the protocols that allow it. May require NSPR.
Line speed emulation
Simulate the variable delays and limited throughput of dial up
connections.
Scripting
Allow more detailed control of protocol tests. It looks
difficult to make this scalable and fast.
Combined tests
Deliver mail over SMTP and then see when it arrives using IMAP.

View File

@@ -1,462 +0,0 @@
#!/bin/ksh
########################################################################
# buildall - automated multi-platform build tool
#
# 10/09/97 - marcel - created
# 10/13/97 - marcel - support shared build tree
# 2/11/98 - marcel - updated for 4.0 Beta builds (need -update)
# 2/26/98 - marcel - added -r, -t and host specifiers
# 7/01/99 - robodan - added VAR=value ability
# 8/01/99 - robodan - explicitly know about building on localhost
# 10/15/99 - robodan - remove older OSes from build list
# 2000/4/7 - robodan - Created mstone version
########################################################################
#
# This script is intended to do a set of UNIX builds for a
# given CVS module. It is designed to use 'rsh' between a
# set of trusting hosts and use shared NFS storage with common
# mount points (e.g. /u/username/...)
#
# To check if you have rights to rsh to a particular host, try:
# rsh hostname "echo $PATH"
# You may have to edit your .rhosts or /etc/hosts.equiv
#
# A target directory will be created based on the current date.
#
# A set of global build logs plus a log per platform are kept
# in a log directory under the target
#
# It will checkout a copy of the source, duplicate it for
# each platform and perform a set of remote builds in parallel.
# The script will exit when all the work has been completed.
#
# Example usage:
# cd ~/src; buildall msg
# Result:
# ~/src/19980210_40.1/
# ~/src/19980210_40.1/logs/...
# ~/src/19980210_40.1/src/...
# ...
#
# Buildhosts
DEFAULT_BUILDHOSTS="kimo nugget vsync shave purgatory trex0"
usage() {
echo ""
echo "usage: buildall [ make assigns... ] < -t | target > [ -r ] [ buildhosts... ]"
echo " [ -t | --test]: just test rsh and report OS versions."
echo " [-r | --respin]: rebuild in place using existing source."
echo " [-p | --postbuild]: Execute post build command too."
echo " [make assigns]: e.g. VARIANT=release"
echo " <target>: one of: mstone42"
echo " [buildhosts...]: default [$DEFAULT_BUILDHOSTS]"
echo ""
exit 1
}
########################################################################
# Set these defaults and options for your desired build
########################################################################
# Target base destination directory
DESTBASE=`pwd`
# Can we do multiple ARCH builds in same source tree
SHARESRC=yes
DESCRIPTION=""
BUILDHOSTS=""
RESPIN="no"
POSTBUILD="no"
JUST_TEST="no"
DESTTYPE=""
CO_CMD="cvs -d $CVSROOT -q checkout"
CHECKOUT=""
CHECKOUT2=""
#MOZCVSROOT=':pserver:anonymous@cvs.mozilla.org:/cvsroot'
MOZCVSROOT=':pserver:robodan%netscape.com@cvs.mozilla.org:/cvsroot'
MAKE="gmake"
MK_ARG=""
ARGS="$@"
for ARG in "$@"; do
# If this is a make assignment (FOO=whatever), add it to make command
# Arguments with quotes in them dont go all the way through.
# Make args trick: 'FOO=nop -j 2'
# The pre-post arg stuff uses hostnames as a switch, ugly calling syntax.
if [[ -n "`echo z$ARG | egrep '^z[A-Z0-9_]+=[^ ]'`" ]] ; then
if [[ -n "$DESCRIPTION" ]] ; then
echo "Arg after target is ignored! ($ARG)"
continue
fi
if [[ -z "$BUILDHOSTS" ]] ; then # pre args
MAKE="$MAKE $ARG"
else # post args
MK_ARG="$MK_ARG $ARG"
fi
continue
fi
# should we just rebuild todays latest source...
if [[ "$ARG" = "-r" || "$ARG" = "--respin" || "$ARG" = "respin" ]]; then
RESPIN="yes"
continue
fi
# should we just run post build command...
if [[ "$ARG" = "-p" || "$ARG" = "--postbuild" || "$ARG" = "postbuild" ]]; then
POSTBUILD="yes"
continue
fi
# should we just test remote connectivity and execute permissions...
if [[ "$ARG" = "-t" || "$ARG" = "--test" ]]; then
JUST_TEST="yes"
RESPIN="yes"
continue
fi
# We will pull source using: "$CHECKOUT"
# And build on each machine: "cd $BUILDDIR && $BUILDCMD"
# expand targets (but dont confuse hosts for targets (msg7))
# These will build just mstone
# expand targets (but dont confuse hosts for targets (msg7))
if [[ "$BUILDCMD" = "" && "$ARG" = mailstone* ]]; then
case ${ARG#mstone} in
"")
"42")
DESTTYPE=_MSTONE42
MS_BRANCH=""
#BUILDCMD="$MAKE $MK_ARG debug release"
#POSTCMD="$MAKE $MK_ARG all_DBG.OBJ all_OPT.OBJ"
BUILDCMD="$MAKE $MK_ARG rpackage"
POSTCMD="$MAKE $MK_ARG all_OPT"
;;
*)
echo "Unknown mstone version in $ARG"
echo "Try mstone42"
exit 1;;
esac
DESCRIPTION="Mstone $MS_BRANCH"
BUILDDIR=./mozilla/mstone
CVSROOT=$MOZCVSROOT
CHECKOUT="$CO_CMD $MS_BRANCH mozilla/mstone"
# BUG No way to unpack perl, gd, and gnuplot before building
continue
fi
#########################
# Other...
#########################
# These will print some tools info
if [[ "$ARG" = "tools" ]]; then
CHECKOUT="$CO_CMD modules"
BUILDDIR=.
BUILDCMD="which gcc && ls -l /tools/ns/bin/gcc && which gcc-2.7.2.1 && ls -l /tools/ns/bin/gcc-2.7.2.1"
continue
fi
#########################
# Everything else is assumed to be a hostname
#########################
BUILDHOSTS="$ARG $BUILDHOSTS"
done # for ARG in $*; do
if [[ "$BUILDHOSTS" = "" ]]; then
BUILDHOSTS=$DEFAULT_BUILDHOSTS
fi
if [[ "$BUILDCMD" = "" && "$JUST_TEST" = "no" ]]; then
usage
fi
########################################################################
# You shouldn't have to modify stuff below here too much
########################################################################
# Who and Where are we
PROG=buildall
RSH=rsh
SYS=`uname -s`
echo SYS=$SYS
if [[ "$SYS" = "HP-UX" ]]; then
RSH=remsh
fi
########################################################################
# Simple log output function
########################################################################
log() {
# echo "[`date +\"%Y/%m/%d %H:%M:%S\"`] $PROG: $*"
echo "`date +\"%H:%M:%S\"` $PROG: $*"
}
########################################################################
# Error
########################################################################
quit() {
log "$* (exiting)..."
exit 1
}
# Where should the work be done
REV=1
WORKDIR=$DESTBASE/`date +"%Y%m%d"`$DESTTYPE.$REV
LASTWORKDIR=$WORKDIR
LASTREV=$REV
while [[ -d $WORKDIR ]]; do
LASTREV=$REV
let "REV= REV + 1"
LASTWORKDIR=$WORKDIR
WORKDIR=$DESTBASE/`date +"%Y%m%d"`$DESTTYPE.$REV
done
if [[ "$RESPIN" = "yes" ]]; then
WORKDIR=$LASTWORKDIR
REV=$LASTREV
fi
BUILDREV=$REV
if [[ ! -d $WORKDIR && "$RESPIN" = "yes" ]]; then
quit "missing expected respin workdir ($WORKDIR)"
fi
mkdir -p $WORKDIR
# Where to send logs
LOGDIR=$WORKDIR/logs
[[ -d $LOGDIR ]] || mkdir $LOGDIR
# What tool to use for compressed tar
if [[ -x /tools/ns/bin/tar ]] ; then # ROBDAN 9-15-98 for Linux
TAR=/tools/ns/bin/tar
else
TAR=tar
fi
SRCDIR=$WORKDIR/src
SRCTAR=$WORKDIR/src.tar.gz
########################################################################
# The function which extracts the source and prepares for copies
########################################################################
prepare_source() {
log "Preparing source code..."
mkdir $SRCDIR
(cd $SRCDIR;
log "Extracting source in $SRCDIR...";
log "$CHECKOUT > $LOGDIR/cvs-co.txt";
$CHECKOUT > $LOGDIR/cvs-co.txt;
RET=$?
if [[ $RET -ne 0 ]]; then quit "### Failed($RET): $CHECKOUT"; fi
if [[ "$CHECKOUT2" != "" ]]; then
log "$CHECKOUT2 >> $LOGDIR/cvs-co.txt";
$CHECKOUT2 >> $LOGDIR/cvs-co.txt;
RET=$?
if [[ $RET -ne 0 ]]; then quit "### Failed($RET): $CHECKOUT2"; fi
fi
log "Listing source...";
ls -Rl > $LOGDIR/src-ls-Rl.txt
log "Archiving source..."
$TAR czf $SRCTAR .
)
RET=$?
if [[ $RET -ne 0 ]]; then
quit "### Failed($RET): cannot prepare source";
else
log "Source extraction complete";
fi
}
########################################################################
# The function which does a build
########################################################################
do_rbuild() {
OSDEST=$1
if [ "$SHARESRC" = "yes" ]; then
RSRCDIR=$SRCDIR
else
RSRCDIR=$WORKDIR/$OSDEST
fi
[[ -d $RSRCDIR ]] || mkdir -p $RSRCDIR
cd $RSRCDIR;
# do any late variable expansions
RAWCMD=$BUILDCMD
BUILDCMD=$(eval echo $RAWCMD)
if [[ $RHOST = localhost ]] ; then
log "Build locally for $OSDEST ($BUILDCMD)...";
cd $BUILDDIR && pwd && $BUILDCMD && echo $PROG: Success
RET=$?
if [[ $RET -ne 0 ]]; then quit "### Failed($RET): $OSDEST build"; fi
log "Completed local build..."
return
fi
if [[ "$SHARESRC" != "yes" ]]; then
log "Extracting source for $OSDEST...";
$RSH $RHOST -n "cd $RSRCDIR && pwd && $TAR xzf $SRCTAR";
RET=$?
if [[ $RET -ne 0 ]]; then quit "### Failed($RET): $OSDEST source extraction"; fi
else
log "Using common source in $RSRCDIR";
fi
log "Building for $OSDEST ($BUILDCMD)...";
$RSH $RHOST -n "cd $RSRCDIR/$BUILDDIR && pwd && $BUILDCMD && echo $PROG: Success"
RET=$?
if [[ $RET -ne 0 ]]; then quit "### Failed($RET): $OSDEST build"; fi
log "Completed $OSDEST...";
}
buildhost() {
RHOST=$1
log "Query $RHOST configuration...";
if [[ $RHOST = localhost ]] ; then
uname -s > /tmp/$$.$RHOST 2>&1
else
$RSH $RHOST -n "uname -s" > /tmp/$$.$RHOST 2>&1
RET=$?
if [[ $RET -ne 0 ]]; then
quit "..[$RHOST] ### Failed($RET): $RSH $RHOST -n \"uname -s\"";
fi
fi
ROSTYPE=`tail -1 /tmp/$$.$RHOST`
if [[ "$ROSTYPE" = "AIX" ]]; then
$RSH $RHOST -n "uname -v" > /tmp/$$.$RHOST 2>&1
ROSTYPE=${ROSTYPE}`tail -1 /tmp/$$.$RHOST`
fi
if [[ $RHOST = localhost ]] ; then
uname -r > /tmp/$$.$RHOST 2>&1
else
$RSH $RHOST -n "uname -r" > /tmp/$$.$RHOST 2>&1
fi
ROSREV=`tail -1 /tmp/$$.$RHOST`
rm /tmp/$$.$RHOST
if [[ $RHOST = localhost ]] ; then
OSDEST=`hostname | cut -f1 -d.`-${ROSTYPE}${ROSREV}
else
OSDEST=${RHOST}-${ROSTYPE}${ROSREV}
fi
log "..Building on [$OSDEST]..."
REV=1 # find unique logfile name
OSLOG=$LOGDIR/$OSDEST.$REV
while [[ -f $OSLOG ]]; do
let "REV = REV + 1"
OSLOG=$LOGDIR/$OSDEST.$REV
done
if [[ "$JUST_TEST" = "yes" ]]; then
echo "$PROG: Success" > $OSLOG
else
( do_rbuild $OSDEST ) > $OSLOG 2>&1
fi
grep "$PROG: Success" $OSLOG > /dev/null
RET=$?
if [[ $RET -eq 0 ]]; then
RESULT="SUCCESS";
else
RESULT="FAILURE($RET)";
fi
log "..Completed [$OSDEST] <$RESULT>.";
}
########################################################################
# The function which initiates all the builds
########################################################################
do_builds() {
log "Launching builds..."
for HOST in $BUILDHOSTS; do
buildhost $HOST &
done
}
########################################################################
# main
########################################################################
main() {
if [[ "$JUST_TEST" = "yes" ]]; then
log "Automated test starting..."
else
log "Automated build of [$DESCRIPTION] starting..."
fi
log ""
log " ARGS = $ARGS"
log " BUILDHOSTS = $BUILDHOSTS"
log " WORKDIR = $WORKDIR"
log " SRCDIR = $SRCDIR"
log " LOGDIR = $LOGDIR"
log " CHECKOUT = $CHECKOUT"
log " BUILDDIR = $BUILDDIR"
log " BUILDCMD = $BUILDCMD"
log " RESPIN = $RESPIN"
log ""
[[ "$RESPIN" = "no" ]] && prepare_source
do_builds
log "Waiting for all builds to complete..."
wait
log "All builds completed."
if [[ -n "$POSTCMD" && "$POSTBUILD" = "yes" ]] ; then
log "Running post build command."
REV=1 # find unique logfile name
POSTLOG=$LOGDIR/postbuild.$REV
while [[ -f $POSTLOG ]]; do
let "REV = REV + 1"
POSTLOG=$LOGDIR/postbuild.$REV
done
echo "Dir $SRCDIR/$BUILDDIR" > $POSTLOG
echo "Cmd $POSTCMD" >> $POSTLOG
(cd $SRCDIR/$BUILDDIR && $POSTCMD && echo $PROG: Success) >> $POSTLOG 2>&1
log "Post build command completed."
elif [[ -n "$POSTCMD" ]] ; then
echo "Skipping post build command: $POSTCMD"
fi
}
REV=1
PROGLOG=$LOGDIR/$PROG.$REV
while [[ -f $PROGLOG ]]; do
REV=`expr $REV + 1`
PROGLOG=$LOGDIR/$PROG.$REV
done
main | tee $PROGLOG 2>&1
exit 0

View File

@@ -1,164 +0,0 @@
@if not "%echo%" == "on" echo off
REM ************ simple autobuild for mailstone
setlocal
set BOTH=0
if not "%1" == "" goto GetTag
set BOTH=1
set TAG=_OPT
goto SetConfig
:GetTag
if %1 == dbg set TAG=_DBG
if %1 == DBG set TAG=_DBG
if %1 == Debug set TAG=_DBG
if %1 == debug set TAG=_DBG
if %1 == Release set TAG=_OPT
if %1 == release set TAG=_OPT
if %1 == opt set TAG=_OPT
if %1 == OPT set TAG=_OPT
if %1 == optimize set TAG=_OPT
if %1 == Optimize set TAG=_OPT
if %1 == optimized set TAG=_OPT
if %1 == Optimized set TAG=_OPT
if %1 == clean goto CleanBoth
:SetConfig
if %TAG% == _DBG set Config=Debug
if %TAG% == _OPT set Config=Release
set ARCH=WINNT4.0%TAG%.OBJ
set FINAL_PATH=built\package\%ARCH%\mailstone
if not "%2" == "clean" if not exist %FINAL_PATH%\nul mkdir %FINAL_PATH%
REM ************ first, clean the binary release
nmake /f mailstone.mak CFG="mailstone - Win32 %Config%" /nologo NO_EXTERNAL_DEPS=1 CLEAN
if not "%2" == "clean" goto BuildMailstone
if exist src\%Config%\nul echo y | rd /s src\%Config% > nul
if exist src\gnuplot-3.7\%Config%\nul echo y | rd /s src\gnuplot-3.7\%Config% > nul
if exist src\gd1.3\%Config%\nul echo y | rd /s src\gd1.3\%Config% > nul
if exist built\%ARCH%\nul echo y | rd /s built\%ARCH% > nul
if exist %FINAL_PATH%\nul echo y | rd /s %FINAL_PATH% > nul
goto done
:BuildMailstone
REM **************** next, build it
nmake /f mailstone.mak CFG="mailstone - Win32 %Config%" /nologo NO_EXTERNAL_DEPS=1
if errorlevel 1 goto BadBuild
REM ************ next, copy the top-level files
copy mstone.bat %FINAL_PATH%
copy setup.bat %FINAL_PATH%
copy CHANGELOG %FINAL_PATH%
copy INSTALL %FINAL_PATH%
copy README %FINAL_PATH%
copy LICENSE %FINAL_PATH%
REM ************ now, copy the files for running mailstone into bin
if not exist %FINAL_PATH%\bin\nul mkdir %FINAL_PATH%\bin
copy built\%ARCH%\mailclient.exe %FINAL_PATH%\bin
if exist built\package\%ARCH%\mailclient.exe copy built\package\%ARCH%\mailclient.exe %FINAL_PATH%\bin
if exist built\package\%ARCH%\mailclient.exe del /f /q built\package\%ARCH%\mailclient.exe
copy bin\*.pl %FINAL_PATH%\bin
REM ************ now, copy the configuration files into conf
if not exist %FINAL_PATH%\conf\nul mkdir %FINAL_PATH%\conf
copy conf\*.* %FINAL_PATH%\conf
REM ************ now, copy the data files into data
if not exist %FINAL_PATH%\data\nul mkdir %FINAL_PATH%\data
copy data\*.msg %FINAL_PATH%\data
REM ************ now, copy the gd files into gd
if not exist %FINAL_PATH%\gd\nul mkdir %FINAL_PATH%\gd
copy src\gd1.3\index.html %FINAL_PATH%\gd\gd.html
REM ************ now, copy the gnuplot files into gnuplot
if not exist %FINAL_PATH%\gnuplot\nul mkdir %FINAL_PATH%\gnuplot
copy built\%ARCH%\gnuplot\gnuplot.exe %FINAL_PATH%\gnuplot
copy src\gnuplot-3.7\Copyright %FINAL_PATH%\gnuplot
copy src\gnuplot-3.7\docs\gnuplot.1 %FINAL_PATH%\gnuplot
REM ************ now, copy the perl files into perl
if not exist %FINAL_PATH%\perl\nul mkdir %FINAL_PATH%\perl
if not exist %FINAL_PATH%\perl\bin\nul mkdir %FINAL_PATH%\perl\bin
if not exist %FINAL_PATH%\perl\lib\nul mkdir %FINAL_PATH%\perl\lib
if not exist %FINAL_PATH%\perl\lib\5.00503\nul mkdir %FINAL_PATH%\perl\lib\5.00503
if not exist %FINAL_PATH%\perl\lib\5.00503\MSWin32-x86\nul mkdir %FINAL_PATH%\perl\lib\5.00503\MSWin32-x86
#copy built\%ARCH%\perl\perl.exe %FINAL_PATH%\perl\bin
#rcp -b sandpit:/share/builds/components/perl5/WINNT-perl5/perl.exe %FINAL_PATH%\perl\bin\perl.exe
#if errorlevel 1 goto BadRcp
#if not exist %FINAL_PATH%\perl\perl.exe goto BadRcp
#rcp -b sandpit:/share/builds/components/perl5/WINNT-perl5/perl300.dll %FINAL_PATH%\perl\bin\perl300.dll
#if errorlevel 1 goto BadRcp
#if not exist %FINAL_PATH%\perl\perl300.dll goto BadRcp
copy src\perl5.005_03\Artistic %FINAL_PATH%\perl
copy c:\perl\5.00503\bin\MSWin32-x86\perl.exe %FINAL_PATH%\perl\bin
copy c:\perl\5.00503\bin\MSWin32-x86\perl.dll %FINAL_PATH%\perl\bin
copy c:\perl\5.00503\lib\*.pm %FINAL_PATH%\perl\lib\5.00503
copy c:\perl\5.00503\lib\*.pl %FINAL_PATH%\perl\lib\5.00503
copy c:\perl\5.00503\lib\MSWin32-x86\*.pm %FINAL_PATH%\perl\lib\5.00503\MSWin32-x86
goto end
:CleanBoth
echo.
echo NOTICE: CLEANING debug build
call autobuild.bat debug clean
echo NOTICE: CLEANING optimized build
call autobuild.bat release clean
echo NOTICE: Removing generated dependency files
del /s *.dep
if exist built\nul echo y | rd /s built > nul
goto done
:BadRcp
echo.
echo ERROR: Failed to rcp perl files over to mailstone packaging
echo ERROR: Two common causes of this are .rhosts permissions or a broken rcp.exe
echo ERROR: Make sure you are not using rcp.exe from NT4.0 SP4
echo ERROR: The SP5 version is available in \\cobra\engineering\bin\rcp_sp5.exe
echo ERROR: Use this version to replace ...\system32\rcp.exe
goto done
:BadBuild
echo.
echo ERROR: Failed to build mailstone
goto done
:end
echo.
if %BOTH% == 0 goto done
if %TAG% == _DBG goto done
set TAG=_DBG
goto SetConfig
:done
endlocal

View File

@@ -1,852 +0,0 @@
# The contents of this file are subject to the Netscape Public
# License Version 1.1 (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 the Netscape Mailstone utility,
# released March 17, 2000.
#
# The Initial Developer of the Original Code is Netscape
# Communications Corporation. Portions created by Netscape are
# Copyright (C) 1997-2000 Netscape Communications Corporation. All
# Rights Reserved.
#
# Contributor(s): Dan Christian <robodan@netscape.com>
# Marcel DePaolis <marcel@netcape.com>
#
# Alternatively, the contents of this file may be used under the
# terms of the GNU Public License (the "GPL"), in which case the
# provisions of the GPL are applicable instead of those above.
# If you wish to allow use of your version of this file only
# under the terms of the GPL and not to allow others to use your
# version of this file under the NPL, indicate your decision by
# deleting the provisions above and replace them with the notice
# and other provisions required by the GPL. If you do not delete
# the provisions above, a recipient may use your version of this
# file under either the NPL or the GPL.
#####################################################
# This file does argument processing, file IO, and other utility routines
# Where the online docs live
#$mailstoneURL =
# "http://home.netscape.com/eng/server/messaging/4.1/mailston/stone.htm";
#$mailstoneURL =
# "http://developer.iplanet.com/docs/manuals/messaging.html";
#$mailstoneURL =
# "http://docs.iplanet.com/docs/manuals/messaging/nms415/mailstone/stone.htm"
$mailstoneURL = "http:doc/MailStone.html";
# Subdirs for results (each under a timestamp dir). Should just hardwire.
$tmpbase = "tmp";
$resultbase = "results";
# This holds everything about the test and system configuration
@workload = ();
# Setup the special CONFIG section
$params{"sectionTitle"} = "CONFIG";
$params{"sectionParams"} = "";
$params{"lineList"} = ();
push @workload, \%params;
# Get the lists discribing the data we process
do 'protoconf.pl' || die "$@\n";
%includedFiles = (); # array of included files
# Utility functions
# Create a unique hash array. Programming Perl, 2nd edition, p291 (p217?)
package ArrayInstance;
sub new {
my $type = shift;
my %params = @_;
my $self = {};
return bless $self, $type;
}
package main;
# run a command in the background, return its PID
# Uses fork: will not run on NT in perl 5.004
# if the server is "localhost", ignore the rcmd part
# if stdin, stdout, and/or stderr is set, redirect those for the sub process
sub forkproc {
my $rcmd = shift;
my $server = shift;
my $command = shift;
my $stdin = shift;
my $stdout = shift;
my $stderr = shift;
if (my $pid = fork()) {
return $pid; # parent
}
# rest of this is in the child
if ($stdin) { # redirect stdin if needed
close (STDIN);
open STDIN, "<$stdin"
|| die "Couldn't open $stdin for input\n";
}
if ($stdout) { # redirect stdout if needed
close (STDOUT);
open STDOUT, ">>$stdout"
|| die "Couldn't open $stdout for output\n";
}
if ($stderr) { # redirect stderr if needed
close (STDERR);
open STDERR, ">>$stderr"
|| die "Couldn't open $stderr for output\n";
}
if ($server =~ /^localhost$/i) {
exec $command;
die "Coundn't exec $command:$!\n";
} else {
exec split (/\s+/, $rcmd), $server, $command;
die "Coundn't exec $rcmd $server $command:$!\n";
}
}
# Relocate file to tmp directory (if it is in the results directory),
# and put a ~ on the end of it.
# ASSUMES tmp and results are on the same partition (on NT, same drive).
# Usage: fileBackup (filename)
sub fileBackup {
my $filename = shift;
my $bfile = $filename;
(-f $filename) || return 0; # file doent exist
$bfile =~ s/$resultbase/$tmpbase/; # move to tmp
$bfile .= "~"; # indicate that this is a backup
(-f $bfile) && unlink ($bfile);
#print "Backing up $filename to $bfile\n"; # DEBUG
rename ($filename, $bfile) || unlink ($filename);
}
# Insert text into a file after a tagline
# fileInsertAfter (filename, tagstring, newtext)
sub fileInsertAfter {
my $filename = shift || die "fileInsertAfter: missing filename";
my $tagline = shift || die "fileInsertAfter: missing tagline";
my $newtext = shift || die "fileInsertAfter: missing text";
my $foundit = 0;
open(OLD, "<$filename") ||
open(OLD, "gunzip -c $filename |") ||
die "fileInsertAfter: Could not open input $filename: $!";
open(NEW, ">$filename+") ||
die "fileInsertAfter: Could not open output $filename+: $!";
while (<OLD>) {
print NEW $_; # copy (including tagline)
next unless (/$tagline/); # matched tagline
print NEW $newtext; # insert new text
$foundit++;
last; # only change first occurance
}
if ($foundit) { # copy rest of file
while (<OLD>) {
print NEW $_;
}
}
close (OLD);
close (NEW);
if ($foundit) {
fileBackup ($filename);
rename ("$filename+", "$filename");
#print "Updated $filename\n"; # DEBUG
return $foundit;
} else {
($params{DEBUG}) && print "No change to $filename\n"; # DEBUG
unlink ("$filename+");
return 0;
}
}
# Do text for text replacements in a file.
# Perl wildcards are automatically quoted.
# fileReplace (filename, matchPat, oldtext, newtext)
sub fileReplaceText {
my $filename = shift || die "fileReplaceText: missing filename";
my $tagline = shift || die "fileReplaceText: missing tagline ($filename)";
my $oldtext = shift;
my $newtext = shift;
my $foundit = 0;
return if ($newtext eq ""); # nothing to do
return if ($oldtext eq ""); # nothing can be done
open(OLD, "<$filename") ||
open(OLD, "gunzip -c $filename |") ||
die "fileReplaceText: Could not open input $filename: $!";
open(NEW, ">$filename+") ||
die "fileReplaceText: Could not open output $filename+: $!";
$oldtext =~ s/([][{}*+?^.\/])/\\$1/g; # quote regex syntax
while (<OLD>) {
if (/$tagline/i) { # matched tagline
$foundit++;
s/$oldtext/$newtext/; # do the replace
}
print NEW $_;
}
close (OLD);
close (NEW);
if ($foundit) {
fileBackup ($filename);
rename ("$filename+", "$filename");
#print "Updated $filename\n"; # DEBUG
return $foundit;
} else {
($params{DEBUG}) && print "No change to $filename\n"; # DEBUG
unlink ("$filename+");
return 0;
}
}
# copy a file to a new name. Handles possible compression. OS independent.
# fileCopy (filename, newname)
sub fileCopy {
my $filename = shift || die "fileReplaceText: missing filename";
my $newname = shift || die "fileReplaceText: missing newname ($filename)";
open(OLD, "<$filename") ||
open(OLD, "gunzip -c $filename |") ||
die "fileReplaceText: Could not open input $filename: $!";
open(NEW, ">$newname") ||
die "fileReplaceText: Could not open output $newname: $!";
while (<OLD>) { # copy it
print NEW $_;
}
close (OLD);
close (NEW);
return 0;
}
# display a file to STDOUT. Handles possible compression
sub fileShow {
my $filename = shift || die "fileShow: missing filename";
open(SHOWIT, "<$filename") ||
open(SHOWIT, "gunzip -c $filename.gz |") ||
die "fileShow: Couldn't open $filename: $!";
while (<SHOWIT>) { print; }
close(SHOWIT);
}
# sub function to figure time extents
# (start, end) = dataMinMax counterName \@protocols oldstarttime oldendtime
# Use 0 for uninitialized start or end
sub dataMinMax {
my $name = shift;
my $protos = shift;
my $start = shift;
my $end = shift;
# make global
# create the plot script and data files
# Figure out the encompassing time extent
foreach $p (@$protos) { # create the plot data files
my @times = sort numeric keys %{ $graphs{$p}->{$name}};
if ($#times <= 0) {
next;
}
if (($start == 0) || ($times[0] < $start)) {
$start = $times[0];
}
if (($end == 0) || ($times[0] > $end)) {
$end = $times[$#times];
}
}
#printf ("Data $name start=$start end=$end (%d points)...\n",
# $end - $start);
return ($start, $end);
}
# simple function to formatted a number into n, n K, n M, or n G
sub kformat {
my $n = shift;
my $r = "";
if ($n > (1024*1024*1024)) {
$r = sprintf "%.2fG", $n / (1024*1024*1024);
} elsif ($n > (1024*1024)) {
$r = sprintf "%.2fM", $n / (1024*1024);
} elsif ($n > 1024) {
$r = sprintf "%.2fK", $n / 1024;
} else {
$r = sprintf "%d ", $n;
}
return $r;
}
# simple function to formatted a time into Ns, Nms, or Nus
# the goal is to make a table of timss uncluttered and easy to read
# I dont convert to minutes or hours because the non-1000x multipliers
# are hard to back solve in your head for comparisons
sub tformat {
my $n = shift;
my $r = "";
if ($n == 0.0) {
$r = "0.0"; # make exactly 0 explicit
} elsif ($n < 0.001) {
$r = sprintf "%.2fus", $n * 1000 * 1000;
} elsif ($n < 1.0) {
$r = sprintf "%.2fms", $n * 1000;
} elsif ($n >= 1000.0) {
$r = sprintf "%.0fs", $n;
} elsif ($n >= 100.0) {
$r = sprintf "%.1fs", $n;
} else {
$r = sprintf "%.3fs", $n;
}
return $r;
}
#Usage: commify (1234567) returns 1,234,567
sub commify { # perl cookbook p64-65
my $text = reverse $_[0];
$text =~ s/(\d\d\d)(?=\d)(?!\d*\.)/$1,/g;
return scalar reverse $text;
}
# subroutine to enable numeric sorts. Programming Perl p218
# Use: sort numeric ...
sub numeric { $a <=> $b; }
# on NT, turn slash to backslash, then print. Else print.
sub pathprint {
my $str = shift;
$str =~ s!/!\\!g if ($params{NT}); # turn slash to back slash
print $str;
}
# figureTimeNumber number
# Given an number like: 60m, 1h, 100s, 4d, 200
# Return 60, 1, 100, 4, 200
sub figureTimeNumber {
my $arg = shift;
($arg =~ /([0-9]+)(s|sec|second|seconds|m|min|minute|minutes|h|hr|hour|hours|d|day|days)$/i)
&& return $1;
return $arg; # return default
}
# figureTimeUnits number, default
# Given an number like: 60m, 1h, 100s, 4d
# Return a string of minutes, hours, seconds, days
# Else return the second argument
sub figureTimeUnits {
my $arg = shift;
($arg =~ /(s|sec|second|seconds)$/i) && return "seconds";
($arg =~ /(m|min|minute|minutes)$/i) && return "minutes";
($arg =~ /(h|hr|hour|hours)$/i) && return "hours";
($arg =~ /(d|day|days)$/i) && return "days";
return shift; # return default
}
# figureTimeSeconds number, defaultUnits
# Given an number like: 60m, 2h, 100s, 4d
# Return 60*60, 2*60*60, 100, 4*24*60*60
sub figureTimeSeconds {
my $arg = shift;
($arg =~ /([0-9]+)(s|sec|second|seconds)$/i) && return $1;
($arg =~ /([0-9]+)(m|min|minute|minutes)$/i) && return (60*$1);
($arg =~ /([0-9]+)(h|hr|hour|hours)$/i) && return (60*60*$1);
($arg =~ /([0-9]+)(d|day|days)$/i) && return (24*60*60*$1);
if ($_) {
my $def = shift;
return $arg * figureTimeSeconds ("1$def"); # return scaled by default
} else {
return $arg; # return it
}
}
# BACK COMPATIBILITY (everything now in the workload file)
# read the testbed conf file, convert to workload sections
# machine, how many processes, how many threads/proc, arch
# only the first 2 fields are required. Lines starting with # are ignored.
# You can include other files using <include conf/filename.tbd>
# exampe:
# client1 5 10 SunOS5.5.1
sub readTestbedFile {
my $filename = shift;
foreach $section (@workload) {
next unless ($section->{sectionTitle} =~ /CLIENT/o);
print "Testbed $filename skipped, clients read in workload\n";
return 1; # clients already read in workload
}
my $level = 0;
if ($_) {
$level = 1 + shift;
die "Too many nested includes ($level) in $filename!"
unless ($level < 100);
}
my $handle = "$filename$level";
open($handle, "<$filename") ||
open($handle, "gunzip -c $filename.gz |") ||
die "Couldn't open testbed $filename: $!";
while(<$handle>) {
chomp;
s/#.*//; # strip any comments from line
m/^\s*$/o && next; # continue if blank line
# handle include statement
if (m/^<(include|INCLUDE)\s+([^\s]+)\s*>/o) {
#print "Including $2 from $filename\n";
readTestbedFile ($2, $level) || die;
next;
}
# get the server name and number of processes
my @line = split(/\s+/);
# create CLIENT entry in workload
my $sparm = ArrayInstance->new();
if ($line[1]) {
$sparm->{"sectionTitle"} = "CLIENT";
$sparm->{"sectionParams"} = "HOSTS=$line[0]";
$sparm->{"PROCESSES"} = $line[1];
$sparm->{"THREADS"} = $line[2] if ($line[2]);
$sparm->{"ARCH"} = $line[3] if ($line[3]);
} else {
$sparm->{"sectionTitle"} = "MONITOR";
$sparm->{"sectionParams"} = "HOSTS=$line[0]";
$sparm->{"COMMAND"} = $line[2];
}
($params{DEBUG})
&& print "<$sparm->{sectionTitle} $sparm->{sectionParams}>\n";
push @workload, $sparm;
}
close ($handle);
}
# BACK COMPATIBILITY (everything now in the saved workload file)
# This is now only needed to process mailstone4.1 runs
sub readConfigFile {
my $filename = shift;
open(CONFIG, "<$filename") ||
open(CONFIG, "gunzip -c $filename.gz |") ||
die "Couldn't open config file $filename: $!";
while(<CONFIG>) {
chomp;
s/#.*//; # strip any comments from line
m/^\s*$/o && next; # continue if blank line
# get the property and value
my @line = split(/=/);
$params{$line[0]} = $line[1];
}
close CONFIG;
}
# read the workload file and store it as a list of hashes
# Each hash always has the fields: sectionTitle and sectionParams
# usage: readWorkloadFile filename, \@list
sub readWorkloadFile {
my $filename = shift || die "readWorkloadFile: Missing file name";
my $plist = shift || die "readWorkloadFile: Missing return list";
my $level = 0; # file inclusion level
my @handles;
my $fh = "$filename$level";
($params{DEBUG}) && print "Reading workload from $filename.\n";
open($fh, "<$filename") ||
open($fh, "gunzip -c $filename.gz |") ||
die "readWorkloadFile Couldn't open testbed $filename: $!";
$includedFiles{$filename} = 1; # mark file as included
my $sparm=0;
my $conline = "";
while($fh) {
while(<$fh>) {
s/#.*//; # strip any comments from line (quoting?)
s/\s*$//; # strip trailing white space
if ($conline) { # utilize line continue
$_ = $conline . "\\\n" . $_;
$conline = "";
}
if (m/\\$/o) { # check for quoted line continue
s/\\$//; #
$conline = $_;
next;
}
s/^\s*//; # strip initial white space
m/^$/o && next; # continue if blank line
# handle include and includeOnce statements
if ((m/^<(include)\s+(\S+)\s*>/i)
|| (m/^<(includeonce)\s+(\S+)\s*>/i)) {
my $incfile = $2;
if (($1 =~ m/^includeonce/i) && ($includedFiles{$incfile})) {
($params{DEBUG})
&& print "readWorkloadFile:includeOnce $incfile already read.\n";
next;
}
($params{DEBUG})
&& print "readWorkloadFile include $incfile from $filename.\n";
$includedFiles{$incfile} = 1; # mark file
push @handles, $fh; # push current handle on to stack
if ($level++ > 99) { # check recursion and make handles unique
die "readWorkloadFile: include level too deep: $filename $level\n";
}
$fh = "$incfile$level";
open($fh, "<$incfile") ||
open($fh, "gunzip -c $incfile.gz |") ||
die "readWorkloadFile Couldn't open testbed file $incfile: $!";
$filename = $incfile; # for error messages
next;
}
if (m!^</(\w+)>$!o) { # end of section
my $end = $1;
unless ($sparm->{"sectionTitle"} =~ /$end/i) {
die "readWorkloadFile Mismatched section $filename: $. '$sparm->{sectionTitle}' '$end'\n";
return 0;
}
($params{DEBUG}) && print "</$sparm->{sectionTitle}>\n";
push @$plist, $sparm;
$sparm = 0;
next;
}
if (m!^<(\w+)\s*(.*)>$!o) { # start of section
my $sec = $1;
my $more = $2;
if ($sparm) {
die "readWorkloadFile Missing section end $filename: $. '$sparm->{sectionTitle}'\n";
}
if ($sec =~ /CONFIG/i) { # special case, map to existing global
$sparm = \%params;
} elsif ($sec =~ /DEFAULT/i) { # special case, only one DEFAULT
if ($defaultSection) { # use existing defaultSection
$sparm = $defaultSection;
} else { # create a new one
$sparm = ArrayInstance->new();
$sparm->{"sectionTitle"} = uc $sec; # ignore case
$sparm->{"lineList"} = ();
$defaultSection = $sparm;
}
} else {
$sparm = ArrayInstance->new();
$sparm->{"sectionTitle"} = uc $sec; # ignore case
$sparm->{"lineList"} = ();
}
$sparm->{"sectionParams"} = $more; # take newest more info
($params{DEBUG})
&& print "<$sparm->{sectionTitle} $sparm->{sectionParams}>\n";
next;
}
# must be in a section, get parameters
unless ($sparm) {
die "readWorkloadFile Entry encountered outside a section $filename: $. $_\n";
return 0;
}
my ($nm, $val) = split (/[\s=]+/, $_, 2);
$nm = uc $nm; # ignore case
($params{DEBUG}) && print " $nm = $val\n";
if ($nm =~ /ACCOUNTFORMAT/) { # BACK COMPATIBILITY
print "WARNING: 'accountFormat' is obsolete. Use 'addressFormat' and 'loginFormat'\n";
$sparm->{"addressFormat"} = $val;
push @{$sparm->{"lineList"}}, "addressFormat $val";
$val =~ s/@.+$//; # strip at and everything after
$sparm->{"loginFormat"} = $val;
push @{$sparm->{"lineList"}}, "loginFormat $val";
next;
} elsif ($nm =~ /NUMACCOUNTS/) { # BACK COMPATIBILITY
print "WARNING: 'numAccounts' is obsolete. Use 'numAddresses' and 'numLogins'\n";
$sparm->{"numAddresses"} = $val;
push @{$sparm->{"lineList"}}, "numAddresses $val";
$sparm->{"numLogins"} = $val;
push @{$sparm->{"lineList"}}, "numLogins $val";
next;
} elsif ($nm =~ /BEGINACCOUNTS/) { # BACK COMPATIBILITY
print "WARNING: 'beginAccounts' is obsolete. Use 'firstAddress' and 'firstLogin'\n";
$sparm->{"firstAddress"} = $val;
push @{$sparm->{"lineList"}}, "firstAddress $val";
$sparm->{"firstLogin"} = $val;
push @{$sparm->{"lineList"}}, "firstLogin $val";
next;
}
push @{$sparm->{"lineList"}}, $_; # save lines in original order
$sparm->{$nm} = $val;
next;
}
close ($fh);
$fh = pop @handles || last; # empty include stack
$filename = $fh;
$sparm = 0; # can only include whole sections
}
return 1; # success
}
# Write out a workload list to a file
# Optionally, pass in a list of sectionTitle's it should ignore
# usage: writeWorkloadFile filename \@list [\@skipList]
sub writeWorkloadFile {
my $filename = shift || die "writeWorkloadFile: Missing file name";
my $plist = shift || die "writeWorkloadFile: Missing return list";
my $skip = shift;
my @skipH;
my $configSeen = 0;
my $defaultSeen = 0;
my @paramH;
if ($skip) {
foreach $s (@$skip) { # turn list into a hash
$skipH{(uc $s)} = $s; # fix case for index
}
}
foreach $s (@workloadParameters) { # turn list into a hash
$paramH{(uc $s)} = $s; # fix case for index
}
($params{DEBUG}) && print "Writing workload to $filename.\n";
unless (open(WORKOUT, ">$filename")) {
die "Couldn't open testbed $filename: $!";
}
foreach $sparm (@$plist) { # each hash reference in the list
if (($skip)
&& ($skipH{$sparm->{"sectionTitle"}})) {
#($params{DEBUG}) &&
#print "Skipping section $sparm->{sectionTitle}\n";
next;
}
# all CONFIG,DEFAULT sections point to the same hash, output once only
if ($sparm->{"sectionTitle"} =~ /^CONFIG$/) {
next if $configSeen;
$configSeen++;
}
if ($sparm->{"sectionTitle"} =~ /^DEFAULT$/) {
next if $defaultSeen;
$defaultSeen++;
}
if ($sparm->{sectionParams}) { # write section with extra args
print WORKOUT "<$sparm->{sectionTitle} $sparm->{sectionParams}>\n";
} else {
print WORKOUT "<$sparm->{sectionTitle}>\n";
}
if ($sparm->{"sectionTitle"} =~ /^(CONFIG|CLIENT)$/) {
# for Config or Client, output the hash to get computed config
foreach $k (sort keys %$sparm) { # output each parameter
# skip sectionTitle and sectionParams
($k =~ /^(sectionTitle|sectionParams|lineList)$/) && next;
printf WORKOUT " %s\t%s\n",
($paramH{$k}) ? $paramH{$k} : $k,
$sparm->{$k};
}
} else { # write out the line list
foreach $l (@{$sparm->{"lineList"}}) {
print WORKOUT " $l\n";
}
}
print WORKOUT "</$sparm->{sectionTitle}>\n\n";
}
close WORKOUT;
}
# Usage: getClientFilename hostname section
sub getClientFilename {
my $cli = shift || die "Missing client name";
my $section = shift || die "Missing section hash";
return "$tmpdir/$cli-$section->{GROUP}.out"
if ($params{USEGROUPS} && $section->{GROUP});
return "$tmpdir/$cli.out"
}
sub setConfigDefaults { # set CONFIG defaults
# These are set after writing out the test copy to avoid clutter
# Path to gnuplot executable
$params{GNUPLOT}="gnuplot/gnuplot"
unless ($params{GNUPLOT});
# This is the directory the client lives in
$params{TEMPDIR} = "/var/tmp"
unless($params{TEMPDIR});
# Set default remote shell
#$params{RSH} = "/usr/bin/rsh"
$params{RSH} = "ssh"
unless($params{RSH});
# Set default remote copy
#$params{RCP} = "/usr/bin/rcp"
$params{RCP} = "scp"
unless($params{RCP});
# Size of generated gifs
$params{CHARTHEIGHT} = 480
unless($params{CHARTHEIGHT});
$params{CHARTWIDTH} = 640
unless($params{CHARTWIDTH});
$params{CHARTPOINTS} = int (($params{CHARTWIDTH}-60)*0.8)
unless($params{CHARTPOINTS});
# The name of the remote executable
$params{CLIENTCOMMAND} = "mailclient"
unless ($params{CLIENTCOMMAND});
# Set default monitoring command
$params{MONITORCOMMAND} = "vmstat %f"
unless($params{MONITORCOMMAND});
# Set default switches to makeusers
$params{MAKEUSERSARGS} = "-4"
unless ($params{MAKEUSERSARGS});
# Figure out @protocols, this sets the report order
@protocols = ();
{
my %skipH;
foreach $s (@nonProtocolSections) { # turn list into a hash
#print "$s ";
$skipH{(uc $s)} = $s; # fix case for index
}
print "\n";
foreach $sparm (@workload) { # each hash reference in the list
next if ($skipH{$sparm->{"sectionTitle"}});
($params{DEBUG}) &&
print "Found protocol ". $sparm->{"sectionTitle"} . "\n";
push @protocols, $sparm->{"sectionTitle"};
# add to skip list so only added once
$skipH{(uc $sparm->{"sectionTitle"})} = $sparm->{"sectionTitle"};
}
}
@protocolsAll = @protocols;
push @protocolsAll, "Total";
# figure out the graphs ???
}
sub parseArgs { # get args
while (@ARGV) {
my $arg = shift(@ARGV);
if ($arg =~ /^-a$/i) { # was undocumented feature in 4.1
$params{ADDGRAPHS} = shift(@ARGV); # extra graphs
next;
}
if ($arg =~ /^-b$/i) {
$params{TITLE} = shift(@ARGV); # banner
next;
}
# BACK COMPATIBILITY (everything now in the saved workload file)
if ($arg =~ /^-c$/i) { # config file, read when encountered
my $configFile = shift(@ARGV);
readConfigFile ($configFile);
next;
}
if ($arg =~ /^-d$/i) {
$params{DEBUG}++; # Debug
next;
}
if ($arg =~ /^-h$/i) { # Help
print "Usage: -w workfile [-t time] [-r ramptime] [-l load] [-v] [-d]\n";
print "\t[-b banner] [-n notes] [-s sysconfigfile] [-a add_graphs_file]\n";
print "\t[-c configfile] [-m machinefile] [-z] [PARAM=value]...\n";
die "Usage";
}
if ($arg =~ /^-l$/i) { # "load", FIX: naming conventions
$params{CLIENTCOUNT} = shift(@ARGV); # desired client count
next;
}
# BACK COMPATIBILITY (everything now in the saved workload file)
if ($arg =~ /^-m$/i) {
$params{TESTBED} = shift(@ARGV); # testbed machines file
next;
}
if ($arg =~ /^-n$/i) {
$params{COMMENTS} = shift(@ARGV); # notes
next;
}
if ($arg =~ /^-r$/i) {
$params{RAMPTIME} = shift(@ARGV); # ramptime
next;
}
if ($arg =~ /^-s$/i) {
$params{SYSCONFIG} = shift(@ARGV); # system config html file
next;
}
if ($arg =~ /^-t$/i) {
$params{TIME} = shift(@ARGV); # test time
next;
}
if ($arg =~ /^-v$/i) {
$params{VERBOSE} = 1; # verbose mode
next;
}
if ($arg =~ /^-w$/i) { # workload file (may occur multiple times)
my $f = shift(@ARGV);
readWorkloadFile ($f, \@workload) || die "Error reading workload: $@\n";
$params{WORKLOAD} = $f;
next;
}
if ($arg =~ /^-z$/i) {
$params{NT} = 1; # NT mode
next;
}
# any other CONFIG parameter: FIELD=value
if ($arg =~ /^(\w+)=(\S.*)$/) {
my $field = uc $1;
$params{$field} = $2;
next;
}
die "Unknown argument '$arg'";
}
if ($params{NT}) { # should use Cwd module
$cwd = `cd`; # NT get current directory
$cwd = `pwd` unless ($cwd); # in case we are really on UNIX
} else {
$cwd = `pwd`; # in case we are really on UNIX
}
chomp $cwd; # strip NL
}
return 1;

View File

@@ -1,317 +0,0 @@
# The contents of this file are subject to the Netscape Public
# License Version 1.1 (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 the Netscape Mailstone utility,
# released March 17, 2000.
#
# The Initial Developer of the Original Code is Netscape
# Communications Corporation. Portions created by Netscape are
# Copyright (C) 1997-2000 Netscape Communications Corporation. All
# Rights Reserved.
#
# Contributor(s): Dan Christian <robodan@netscape.com>
# Marcel DePaolis <marcel@netcape.com>
#
# Alternatively, the contents of this file may be used under the
# terms of the GNU Public License (the "GPL"), in which case the
# provisions of the GPL are applicable instead of those above.
# If you wish to allow use of your version of this file only
# under the terms of the GPL and not to allow others to use your
# version of this file under the NPL, indicate your decision by
# deleting the provisions above and replace them with the notice
# and other provisions required by the GPL. If you do not delete
# the provisions above, a recipient may use your version of this
# file under either the NPL or the GPL.
#####################################################
# This file deals with the graphs data only
# Interfaces to gnuplot to generate gifs for HTML inclusion.
# Type of images to hold plots (e.g. png, gif, jpeg, svg, tiff, pbm, etc)
unless ($params{IMAGETYPE}) {
# Should probe gnuplot and see if it can generate one of:
# png, gif, jpeg, svg, tiff, or pbm.
# Not all the programs that use args.pl need this (or have gnuplot, yet)
my $outfile = "$tmpbase/termtypes.out";
my %types = (); # hash of interesting types that we spot
unless (open(NEW, "<$outfile")) { # re-use old file if present
($params{DEBUG}) &&
print "Asking gnuplot what output types it supports\n";
my $infile = "$tmpbase/setterm.gpt";
open (NEW, ">$infile") ||
die "genPlot: Could not open output $infile: $!";
print NEW "set terminal";
close (NEW);
# Redirect STDIN, and STDERR
open SAVEIN, "<STDIN";
open STDIN, "<$infile"
|| die "Coundn't open $infile for input\n";
open SAVEERR, ">&STDERR";
open STDERR, ">$outfile"
|| die "Couldnt open $outfile for output\n";
system $params{GNUPLOT}; # gnuplot < $infile 2> $outfile
# Restore STDERR and STDIN
close STDERR;
open STDERR, ">&SAVEERR";
open STDIN, "<SAVEIN";
open(NEW, "<$outfile") ||
die ": Could not open gnuplot output for parsing ($outfile): $!";
unlink ($infile); # clean up
}
# now check through the output for terminal types we can use.
# I havent verified the jpeg or tiff types. e-mail me success or failure
while (<NEW>) {
(/\spng\s/) && ++$types{"png"} && next;
(/\sgif\s/) && ++$types{"gif"} && next;
(/\sjpeg\s/) && ++$types{"jpeg"} && next;
(/\ssvg\s/) && ++$types{"svg"} && next;
(/\stiff\s/) && ++$types{"tiff"} && next;
(/\spbm\s/) && ++$types{"pbm"} && next;
}
close (NEW);
($params{DEBUG}) &&
print "Found these gnuplot types: " . (join " ", (keys %types)) . "\n";
# The ordering here determines our preferences
# This list is by likely browser compatibility and image compactness
# png is about 10x smaller than gif
# svg is smooth and scalable but usually requires a plug-in
# jpeg will probably look bad, but will be directly supported
if ($types{"png"}) { $params{IMAGETYPE}="png"; }
elsif ($types{"gif"}) { $params{IMAGETYPE}="gif"; }
elsif ($types{"jpeg"}) { $params{IMAGETYPE}="jpeg"; }
elsif ($types{"svg"}) { $params{IMAGETYPE}="svg"; }
elsif ($types{"tiff"}) { $params{IMAGETYPE}="tiff"; }
elsif ($types{"pbm"}) { $params{IMAGETYPE}="pbm"; }
else {
die "Gnuplot doesn't support any good image types. Check $outfile.\n";
}
# leave the output file around to speed up repeat runs
}
# sub function to write data files, fire off gnuscript, and clean up
# Uses global startTime and endTime figured above
# genPlot counterName title label \@protocols \@variables
sub genPlot {
my $name = shift;
my $title = shift;
my $label = shift;
my $protos = shift || die "genPlot: '$name' missing protocols";
my $f = shift;
my $vars = shift || die "genPlot: '$name' missing vars";
my $runlist = "";
my $totPoints = 0;
my $totProtos = 0;
my @realProtos;
my @goodProtos;
# user fewer data points than pixels to look good.
# on 640x480 gif, the graph is about 579x408
my $maxData = int (($params{CHARTWIDTH}-60) * 0.9);
my $averageCnt = int (($endTime - $startTime + ($maxData - 1))/$maxData);
if ($averageCnt < 1) { $averageCnt = 1; } # must be a positive int
($params{DEBUG}) && print "$name: averageCnt=$averageCnt vars = @$vars \n";
foreach $p (@$protos) { # First see if there is anything to graph
($p =~ /^Total$/o) && next; # derived if needed
my $pPoints = 0;
my $gp = $graphs{$p};
ALLVAR: foreach $vm (@$vars) {
my $vp = ($f) ? $gp->{$vm}->{$f} : $gp->{$vm};
unless (($vp) && (scalar %$vp)) {
#print "genplot Checking: $p $vm $f => NO\n";
next;
}
#print "genplot Checking: $p $vm $f => ";
foreach $time (keys %$vp) {
next unless ($vp->{$time} != 0);
$totPoints++;
$pPoints++;
#print "VALUES\n";
last ALLVAR;
}
#print "nothing\n"
}
if ($pPoints > 0) { # count how many protocols have non 0
$totProtos++;
push @goodProtos, $p;
}
}
($params{DEBUG}) && print "\tprotocols: @goodProtos\n";
if ($totPoints == 0) { # nothing in any protocol
print "No data for graph '$name', variables '@$vars'\n";
return 0;
}
foreach $p (@$protos) {
unlink ("$tmpdir/$name.$p"); # remove any previous runs
(($p =~ /^Total$/o) && ($totProtos <= 1))
&& next; # skip Totally if only 1 protocol plus total
($p !~ /^Total$/o) && push @realProtos, $p; # everything but Total
# if ($p =~ /^Total$/o) { # move from last to first
# $runlist = "\'$name.$p\' with lines, " . $runlist;
# next;
# }
$runlist .= ", " if ($runlist); # later ones
$runlist .= "\'$name.$p\' with lines";
}
$totPoints = 0;
foreach $p (@realProtos) { # create the plot data files
open(DATA, ">$tmpdir/$name.$p") ||
die "Can't open $tmpdir/$name.$p:$!";
my $gp = $graphs{$p};
my $n = 0;
my $s = 0.0;
my $sTime = 0.0;
my $vp = ($f) ? $gp->{$vars->[0]}->{$f} : $gp->{$vars->[0]};
# foreach $time (sort numeric keys %$vp) {
for (my $tm = $startTime; $tm <= $endTime; $tm++) {
my $v = 0.0;
foreach $vm (@$vars) {
$vp = ($f) ? $gp->{$vm}->{$f} : $gp->{$vm};
$totPoints++;
# due to optimization in updateDelta,
# 0 entries are undefined (also avoids warning)
$v += ($vp->{$tm}) ? $vp->{$tm} : 0;
# if ($vp->{$tm} < 0) {
# print $name, ": proto=", $p, " var=", $vm,
# " value=", $vp->{$tm}, "\n";
# }
}
$s += $v;
$n += 1;
if ($n == 1) { # NOTE: shifts left in sliding window
$sTime = $tm-$startTime;
}
if ($n >= $averageCnt) {
printf (DATA "%d %f\n", $sTime * $timeStep, $s/$n);
$n = 0;
$s = 0.0;
}
}
if ($n > 0) { # handle end case
printf (DATA "%d %f\n", $sTime * $timeStep, $s/$n);
}
close(DATA);
}
#($params{DEBUG}) && print "\tpoints: $totPoints\n";
# need to handle "Total" case
# read the other files and write out the sum
# FIX: total my be mis-aligned with data
if (($#$protos > $#realProtos) && ($totProtos > 1)) {
unlink ("$tmpdir/$name.Total");
open(DATA, ">$tmpdir/$name.Total") ||
die "Can't open $tmpdir/$name.Total:$!";
foreach $r (@goodProtos) { # get file handles
open($r, "$tmpdir/$name.$r")
|| die "Couldn't open $tmpdir/$name.$r: $!";
}
# ASSUMES files are identical in order
my $first = shift @goodProtos;
# print "First protocol: $first Rest: @realProtos\n";
while (<$first>) {
my ($t, $s) = split ' ', $_;
foreach $r (@goodProtos) { # get file handles
$l = <$r>;
if ($l) {
my ($tt, $v) = split ' ', $l;
$t = $tt unless ($t); # in case first proto missing time
$s += $v;
}
}
printf (DATA "%d %f\n", $t, $s);
}
foreach $r (@goodProtos) { close($r); }
close (DATA);
}
# Create a script to feed to gnuplot, which creates a .gif graph.
$runTime = ($endTime - $startTime + 1) * $timeStep;
unlink("$tmpdir/$name.gpt");
open(SCRIPT, ">$tmpdir/$name.gpt")
|| die "Can't open $tmpdir/$name.gpt:$!";
$gnuplot = $params{GNUPLOT};
if ($gnuplot !~ /^\//) { # if not absolute, adjust for cd $tmpbase
$gnuplot = "../../$gnuplot"; # ASSUME $tmpbase is single dir
}
#print "gnuplot is $gnuplot $params{GNUPLOT}\n";
my $varstring = ""; # create display version of names
foreach $t (@$vars) {
$varstring .= ", " if ($varstring);
$varstring .= ($timerNames{$t}) ? $timerNames{$t} : $t;
}
# Setup output "terminal type"
if ($params{IMAGETYPE} eq "gif") { # gif type has different arguments
print SCRIPT "set terminal $params{IMAGETYPE} small size $params{CHARTWIDTH},$params{CHARTHEIGHT}\n";
} elsif ($params{IMAGETYPE} eq "svg") { # svg type has different args too
print SCRIPT "set terminal $params{IMAGETYPE} size $params{CHARTWIDTH} $params{CHARTHEIGHT}\n";
} else { # most types work like this
print SCRIPT "set terminal $params{IMAGETYPE} small color\n";
if (($params{CHARTWIDTH} != 640) || ($params{CHARTHEIGHT} != 480)) {
my $xscale = $params{CHARTWIDTH} / 640;
my $yscale = $params{CHARTHEIGHT} / 480;
print SCRIPT "set size $xscale,$yscale\n";
}
}
print SCRIPT<<"!GROK!THIS!";
set output "../../$resultdir/$name.$params{IMAGETYPE}" # ASSUME $tmpbase is single dir
set autoscale
set xlabel "Test time (seconds)"
set ylabel "$label"
set title "$title ($varstring) -- $params{TSTAMP}"
plot [0:$runTime] $runlist
!GROK!THIS!
close(SCRIPT);
# run script from tmpbase to clean up line labeling
# my $olddir=getcwd();
chdir $tmpdir;
system (split (/\s/, $gnuplot), "$name.gpt");
chdir "../..";
# chdir $olddir;
unless ($params{DEBUG}) {
# cleanup the plot data (or leave around for debugging)
foreach $p (@$protos) {
unlink("$tmpdir/$name.$p");
}
unlink("$tmpdir/$name.gpt");
}
return 1;
}
return 1;

View File

@@ -1,576 +0,0 @@
#!/usr/bin/perl
# The contents of this file are subject to the Netscape Public
# License Version 1.1 (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 the Netscape Mailstone utility,
# released March 17, 2000.
#
# The Initial Developer of the Original Code is Netscape
# Communications Corporation. Portions created by Netscape are
# Copyright (C) 1997-2000 Netscape Communications Corporation. All
# Rights Reserved.
#
# Contributor(s): Dan Christian <robodan@netscape.com>
# Marcel DePaolis <marcel@netcape.com>
# Mike Blakely
#
# Alternatively, the contents of this file may be used under the
# terms of the GNU Public License (the "GPL"), in which case the
# provisions of the GPL are applicable instead of those above.
# If you wish to allow use of your version of this file only
# under the terms of the GPL and not to allow others to use your
# version of this file under the NPL, indicate your decision by
# deleting the provisions above and replace them with the notice
# and other provisions required by the GPL. If you do not delete
# the provisions above, a recipient may use your version of this
# file under either the NPL or the GPL.
#####################################################
# see setup.pl for full usage
# mailmaster [-d] [-c <config file>] ...
# This script reads in the client configuration files and will
# fork children to rsh the mailclient process on network clients,
# each child will write test results to /mailstone directory before
# dying. The parent will the read and combine the results.
#
# Make sure the user running this script has rsh privilege across
# all client machines
print "Netscape Mailstone version 4.2\n";
print "Copyright (c) Netscape Communications Corp. 1997-2000\n";
# this parses the command line and config file
do 'args.pl'|| die "$@\n";
parseArgs(); # parse command line
{ # get unique date string
my ($sec, $min, $hour, $mday, $mon, $year) = localtime;
my $tstamp = sprintf ("%04d%02d%02d.%02d%02d",
1900+$year, 1+$mon, $mday, $hour, $min);
if ( -d "$resultbase/$tstamp") { # check for runs within a minute
my $tail = 'a';
while ( -d "$resultbase/$tstamp$tail" ) { $tail++; }
$tstamp .= $tail;
}
$params{TSTAMP} = $tstamp;
}
$resultdir = "$resultbase/$params{TSTAMP}";
$tmpdir = "$tmpbase/$params{TSTAMP}";
$resultstxt = "$resultdir/results.txt";
$resultshtml = "$resultdir/results.html";
mkdir ("$resultbase", 0775);
mkdir ("$tmpbase", 0775);
mkdir ("$resultdir", 0775);
mkdir ("$tmpdir", 0775);
# Make sure we have everything
die "Must specify the test time" unless $params{TIME};
die "Must specify a workload file" unless $params{WORKLOAD};
if ($params{TESTBED}) { # BACK COMPATIBILITY
readTestbedFile ($params{TESTBED}) || die "Error reading testbed: $@\n";
}
$testsecs = figureTimeSeconds ($params{TIME}, "seconds");
# figure out the processes and thread, given the desired number
# takes into account all the constraints. todo can be a float.
sub figurePT {
my $sec = shift;
my $todo = shift;
my $p = 1; # first guess
my $t = 1;
my $start = 1; # initial process guess
my $end = 250; # highest process guess
if ($todo < 1) { # mark this client as inactive
$sec->{PROCESSES} = 0;
$sec->{THREADS} = 0;
return 0;
}
if (($section->{MAXCLIENTS}) && ($todo > $section->{MAXCLIENTS})) {
$todo = $section->{MAXCLIENTS}; # trim to max client per host
}
if ($section->{PROCESSES}) { # they set this part already
$start = int ($section->{PROCESSES});
$end = $start;
$p = $start;
my $slist = $section->{sectionParams};
$slist =~ s/HOSTS=\s*//; # strip off initial bit
print "Using specified $p processes for clients $slist\n";
}
$end = int ($section->{MAXPROCESSES})
if ($section->{MAXPROCESSES}); # they set a max
if (($params{NT}) || ($section->{ARCH} eq "NT4.0")) {
$end = 1; # # NT is currently limited to 1 process
$start = 1;
$p = 1;
}
# step through some process counts
# it should first reduce errors due to MAXTHREADS,
# the it will reduce errors due to integer math.
# not optimal, just good enough
my $misses = 0;
for (my $n = $start; $n <= $end; $n++) { # try some process counts
my $tryt = int ($todo / $n);
if (($sec->{MAXTHREADS}) && ($tryt > $sec->{MAXTHREADS})) {
$tryt = $sec->{MAXTHREADS};
}
# see if this is a better match than the last one
if (abs ($todo - ($n * $tryt)) < abs ($todo - ($p * $t))) {
$p = $n;
$t = $tryt;
$misses = 0;
} else {
$misses++;
last if ($misses > 1); # getting worse
}
}
$sec->{PROCESSES} = $p;
$sec->{THREADS} = $t;
return $p * $t;
}
# Allocate CLIENTCOUNT to the client machines
# try NOT to turn this into a massive linear programming project
# works best to put bigger machines last
if ($params{CLIENTCOUNT}) {
my $todo = $params{CLIENTCOUNT};
my $softcli = 0; # how many can we play with
foreach $section (@workload) { # see which are already fixed
next unless ($section->{sectionTitle} =~ /CLIENT/o);
unless (($section->{PROCESSES}) && ($section->{THREADS})) {
$softcli++;
next;
}
my $slist = $section->{sectionParams};
$slist =~ s/HOSTS=\s*//; # strip off initial bit
my @hlist = split /[\s,]/, $slist;
my $hcnt = (1 + $#hlist);
# subtract fixed entries
my $tcount = ($section->{THREADS}) ? $section->{THREADS} : 1;
$todo -= $tcount * $section->{PROCESSES} * $hcnt;
$clientProcCount += $section->{PROCESSES} * $hcnt; # total processes
$params{DEBUG} &&
print "Fixed load group with $hcnt hosts: $section->{PROCESSES} x $tcount\n";
}
$params{DEBUG} &&
print "Allocating $todo clients over $softcli groups\n";
if ($softcli) {
foreach $section (@workload) {
next unless ($section->{sectionTitle} =~ /CLIENT/o);
next if (($section->{PROCESSES}) && ($section->{THREADS}));
my $slist = $section->{sectionParams};
$slist =~ s/HOSTS=\s*//; # strip off initial bit
my @hlist = split /[\s,]/, $slist;
my $hcnt = (1 + $#hlist);
#print "todo=$todo softcli=$softcli hcnt=$hcnt\n";
$todo -= $hcnt * figurePT ($section, $todo / ($softcli * $hcnt));
$clientProcCount += $hcnt * $section->{PROCESSES}; # total procs
$softcli--;
last if ($softcli <= 0); # should not happen
}
}
if ($todo) {
print "Warning: Could not allocate $todo of $params{CLIENTCOUNT} clients.\n";
$params{CLIENTCOUNT} -= $todo;
}
} else { # figure out the client count
my $cnt = 0;
foreach $section (@workload) { # see which are already fixed
next unless ($section->{sectionTitle} =~ /CLIENT/o);
next unless ($section->{PROCESSES});
my $slist = $section->{sectionParams};
$slist =~ s/HOSTS=\s*//; # strip off initial bit
my @hlist = split /[\s,]/, $slist;
my $hcnt = (1 + $#hlist);
# subtract fixed entries
my $tcount = ($section->{THREADS}) ? $section->{THREADS} : 1;
$cnt += $tcount * $section->{PROCESSES} * $hcnt;
$clientProcCount += $section->{PROCESSES} * $hcnt; # total processes
}
$params{CLIENTCOUNT} = $cnt;
die "No clients configured!\n" unless ($cnt > 0);
}
# This has to be written into save workload file for later processing
unless ($params{FREQUENCY}) { # unless frequency set on command line
my $chartp = ($params{CHARTPOINTS}) ? $params{CHARTPOINTS} : 464;
# approximate data points for good graphs (up to 2 times this)
$params{FREQUENCY} = int ($testsecs / $chartp);
if ($params{FREQUENCY} < 2) { # fastest is every 2 seconds
$params{FREQUENCY} = 2;
} elsif ($params{FREQUENCY} > 60) { # slowest is every minute
$params{FREQUENCY} = 60;
}
}
{ # set a unique block id on every section
my $id = 0;
my $configSeen = 0;
my $defaultSeen = 0;
foreach $section (@workload) {
if ($section->{"sectionTitle"} =~ /^CONFIG$/) {
next if $configSeen;
$configSeen++;
}
if ($section->{"sectionTitle"} =~ /^DEFAULT$/) {
next if $defaultSeen;
$defaultSeen++;
}
$id++; # number 1, 2, ...
if ($section->{"sectionTitle"} =~ /^(CONFIG|CLIENT)$/) {
$section->{BLOCKID} = $id;
} else {
push @{$section->{"lineList"}}, "blockID\t$id\n";
}
}
}
# Write the version we pass to mailclient
writeWorkloadFile ("$resultdir/work.wld", \@workload,
\@scriptWorkloadSections);
# Write the complete inclusive version
writeWorkloadFile ("$resultdir/all.wld", \@workload);
setConfigDefaults(); # pick up any missing defaults
unless ($#protocolsAll > 0) {
die "No protocols found. Test Failed!\n";
}
print "Starting: ", scalar(localtime), "\n";
# redirect STDERR
open SAVEERR, ">&STDERR";
open(STDERR, ">$resultdir/stderr") || warn "Can't redirect STDERR:$!\n";
$totalProcs = 0; # number of clients started
# iterate over every client in the testbed, complete the cmd and rsh
if ($params{NT}) { # single client on local host
pathprint ("Starting clients (errors logged to $resultdir/stderr)\n");
foreach $section (@workload) {
next unless ($section->{sectionTitle} =~ /CLIENT/o);
my $tcount = ($section->{THREADS}) ? $section->{THREADS} : 1;
# Build the initial Mailclient command line
my $preCmd = ($section->{COMMAND})
? $section->{COMMAND} : $params{CLIENTCOMMAND};
$preCmd .= " -s -t $params{TIME} -f $params{FREQUENCY}";
$preCmd .= " -d" if ($params{DEBUG});
$preCmd .= " -r" if ($params{TELEMETRY});
$preCmd .= " -R $params{RAMPTIME}" if ($params{RAMPTIME});
$preCmd .= " -m $params{MAXERRORS}" if ($params{MAXERRORS});
$preCmd .= " -M $params{MAXBLOCKS}" if ($params{MAXBLOCKS});
$preCmd .= " -n 1 -N $tcount";
$preCmd .= ($params{USEGROUPS} && $section->{GROUP})
? " -H $section->{GROUP}" : " -H $cli";
my $stdout = "$tmpdir/localhost.out";
$totalProcs += $tcount;
do 'makeindex.pl' || warn "$@\n"; # html index
printf "\nTest duration: %d %s. Rampup time: %d %s. Number of clients: %d\n",
figureTimeNumber ($params{TIME}),
figureTimeUnits ($params{TIME}, "seconds"),
figureTimeNumber ($params{RAMPTIME}),
figureTimeUnits ($params{RAMPTIME}, "seconds"),
$totalProcs;
print STDERR "localhost: cd $params{TEMPDIR}; $preCmd\n";
# Redirect STDIN, and STDOUT
#open SAVEIN, "<STDIN";
open STDIN, "<$resultdir/work.wld"
|| die "Coundn't open $resultdir/work.wld for input\n";
open SAVEOUT, ">&STDOUT";
open STDOUT, ">$stdout"
|| die "Couldnt open $stdout for output\n";
chdir $params{TEMPDIR} || die "Could not cd $params{TEMPDIR}: $!\n";
system $preCmd;
close STDOUT;
open STDOUT, ">&SAVEOUT";
printf "Test done.\n";
chdir $cwd || die "Could not cd $cwd: $!\n";
last; # only do the first one
}
} else { # not NT (forking works)
foreach $section (@workload) { # do pre run commands
next unless ($section->{sectionTitle} =~ /PRETEST/o);
unless ($section->{COMMAND}) {
print "PreTest with no Command for $section->{sectionParams}\n";
next;
}
my $slist = $section->{sectionParams};
$slist =~ s/HOSTS=\s*//; # strip off initial bit
my $myCmd = $section->{COMMAND};
$myCmd =~ s/%f/$params{FREQUENCY}/; # fill in frequency variable
if ($myCmd =~ m/%c/o) { # dont force down if count is used
$count = $testsecs / $params{FREQUENCY};
$myCmd =~ s/%c/$count/; # fill in count variable
}
my $rsh = ($section->{RSH}) ? $section->{RSH} : $params{RSH};
foreach $cli (split /[\s,]/, $slist) {
print "Running pre test command on $cli\n";
open PRE, ">>$resultdir/$cli-pre.log";
print PRE "========\n";
print PRE "$myCmd\n";
print PRE "========\n";
close PRE;
print STDERR "$cli: $myCmd\n"; # log the actual command
forkproc ($rsh, $cli, $myCmd,
"/dev/null", "$resultdir/$cli-pre.log");
}
foreach $cli (split /[\s,]/, $slist) {
wait(); # run multiple PRETEST section sequentially
}
}
foreach $section (@workload) { # start monitors
next unless ($section->{sectionTitle} =~ /MONITOR/o);
my $slist = $section->{sectionParams};
$slist =~ s/HOSTS=\s*//; # strip off initial bit
my $myCmd = ($section->{COMMAND})
? $section->{COMMAND} : $params{MONITORCOMMAND};
my $forceDown = 0;
$myCmd =~ s/,/ /g; # turn commas into spaces BACK COMPATIBIILITY
$myCmd =~ s/%f/$params{FREQUENCY}/; # fill in frequency variable
if ($myCmd =~ m/%c/o) { # dont force down if count is used
$count = $testsecs / $params{FREQUENCY};
$myCmd =~ s/%c/$count/; # fill in count variable
} else {
$forceDown = 1;
}
my $rsh = ($section->{RSH}) ? $section->{RSH} : $params{RSH};
foreach $cli (split /[\s,]/, $slist) {
printf "Monitoring on $cli\n";
open PRE, ">>$resultdir/$cli-run.log";
print PRE "========\n";
print PRE "$myCmd\n";
print PRE "========\n";
close PRE;
print STDERR "$cli: $myCmd\n"; # log the actual command
$pid = forkproc ($rsh, $cli, $myCmd,
"/dev/null", "$resultdir/$cli-run.log");
push @forceDownPids, $pid if ($forceDown); # save PID for shutdown
}
}
print "Starting clients (errors logged to $resultdir/stderr)\n";
foreach $section (@workload) {
next unless ($section->{sectionTitle} =~ /CLIENT/o);
next unless ($section->{PROCESSES}); # unused client
my $slist = $section->{sectionParams};
$slist =~ s/HOSTS=\s*//; # strip off initial bit
my $rsh = ($section->{RSH}) ? $section->{RSH} : $params{RSH};
my $pcount = $section->{PROCESSES};
my $tcount = ($section->{THREADS}) ? $section->{THREADS} : 0;
my $tempdir;
if ($section->{TEMPDIR}) {
$tempdir = $section->{TEMPDIR};
} elsif ($params{TEMPDIR}) {
$tempdir = $params{TEMPDIR};
}
my $preCmd = "./" . (($section->{COMMAND})
? $section->{COMMAND} : $params{CLIENTCOMMAND});
$preCmd .= " -s -t $params{TIME} -f $params{FREQUENCY}";
$preCmd .= " -d" if ($params{DEBUG});
$preCmd .= " -r" if ($params{TELEMETRY});
$preCmd .= " -R $params{RAMPTIME}" if ($params{RAMPTIME});
if ($params{MAXERRORS}) {
# distribute error count over processes, rounding up
my $n = int (($params{MAXERRORS} + $clientProcCount - 1)
/ $clientProcCount);
$n = 1 if ($n < 1);
$preCmd .= " -m $n";
}
if ($params{MAXBLOCKS}) {
# distribute block count over processes, rounding up
my $n = int (($params{MAXBLOCKS} + $clientProcCount - 1)
/ $clientProcCount);
$n = 1 if ($n < 1);
$preCmd .= " -M $n";
}
$preCmd = "cd $tempdir; " . $preCmd if ($tempdir);
$preCmd .= " -n $pcount";
$preCmd =~ s!/!\\!g if ($section->{ARCH} eq "NT4.0");
$preCmd =~ s/;/&&/g if ($section->{ARCH} eq "NT4.0");
foreach $cli (split /[\s,]/, $slist) {
my $stdout = getClientFilename ($cli, $section);
my $myCmd = $preCmd;
$myCmd .= ($params{USEGROUPS} && $section->{GROUP})
? " -H $section->{GROUP}" : " -H $cli";
if ($tcount) {
$myCmd .= " -N $tcount";
printf "Starting %d x %d on $cli\n", $pcount, $tcount;
$totalProcs += $pcount * $tcount;
} else {
printf "Starting %d processes on $cli\n", $pcount;
$totalProcs += $pcount;
}
print STDERR "$cli: $myCmd\n"; # log the actual command
$pid = forkproc ($rsh, $cli, $myCmd,
"$resultdir/work.wld", $stdout);
push @localPids, $pid if ($cli =~ /^localhost$/i);
}
}
if (@localPids) {
# print "Trapping extraneous local signals\n";
# This doesnt trap quite right. We dont die, but shell returns...
$SIG{ALRM} = 'IGNORE'; # in case we get an ALRM from the mailclient
}
printf "\nTest duration: %d %s. Rampup time: %d %s. Number of clients: %d\n",
figureTimeNumber ($params{TIME}),
figureTimeUnits ($params{TIME}, "seconds"),
figureTimeNumber ($params{RAMPTIME}),
figureTimeUnits ($params{RAMPTIME}, "seconds"),
$totalProcs;
do 'makeindex.pl' || warn "$@\n"; # html index
print "Waiting for test to finish.\n";
print "Waiting: ", scalar(localtime), "\n";
# wait for children to finish
$pid = wait();
if (@forceDownPids) { # shut down after the first return.
print "Shutting down @forceDownPids\n";
kill 1 => @forceDownPids; # sigHUP
# kill 9 => @forceDownPids; # sigTERM
}
while ($pid != -1) { # wait for all children
$pid = wait();
}
foreach $section (@workload) { # do post test commands
next unless ($section->{sectionTitle} =~ /POSTTEST/o);
unless ($section->{COMMAND}) {
print "PostTest with no command for $section->{sectionParams}\n";
next;
}
my $slist = $section->{sectionParams};
$slist =~ s/HOSTS=\s*//; # strip off initial bit
my $myCmd = $section->{COMMAND};
$myCmd =~ s/%f/$params{FREQUENCY}/; # fill in frequency variable
if ($myCmd =~ m/%c/o) { # dont force down if count is used
$count = $testsecs / $params{FREQUENCY};
$myCmd =~ s/%c/$count/; # fill in count variable
}
my $rsh = ($section->{RSH}) ? $section->{RSH} : $params{RSH};
foreach $cli (split /[\s,]/, $slist) {
printf "Running post test command on $cli\n";
open PRE, ">>$resultdir/$cli-post.log";
print PRE "========\n";
print PRE "$myCmd\n";
print PRE "========\n";
close PRE;
print STDERR "$cli: $myCmd\n"; # log the actual command
forkproc ($rsh, $cli, $myCmd,
"/dev/null", "$resultdir/$cli-post.log");
}
foreach $cli (split /[\s,]/, $slist) {
wait(); # run multiple POSTTEST section sequentially
}
}
}
print STDERR "\nDone.\n";
close(STDERR);
open STDERR, ">&SAVEERR";
print "\nClients done: ", scalar(localtime), "\n";
print "Collecting results\n";
do 'reduce.pl' || die "$@\n"; # generate graphs and sums
print "Generating results pages\n";
do 'report.pl' || die "$@\n";
# Now display that data to console
if ($params{VERBOSE}) {
fileShow ($resultstxt);
print "\n";
}
print "Processing done: ", scalar (localtime), "\n";
pathprint ("\nResults (text):\t$resultstxt\n");
pathprint ( "Results (HTML):\t$resultshtml\n");
print "Index of runs: \tfile://$cwd/$resultbase/index.html\n";
# Now check for major problems in the stderr file
if (open(RESULTSTXT, "$resultdir/stderr")) {
$ERRCNT=0;
while (<RESULTSTXT>) { $ERRCNT++; }
close(RESULTSTXT);
pathprint ("Error log ($ERRCNT lines):\t$resultdir/stderr\n");
}
{ # list user requested logging
my @logfiles = <$resultdir/*-pre.log>;
if (@logfiles) {
foreach $f (@logfiles) {
print "Pre test log: \t$f\n";
}
}
@logfiles = <$resultdir/*-run.log>;
if (@logfiles) {
foreach $f (@logfiles) {
print "Monitoring log: \t$f\n";
}
}
@logfiles = <$resultdir/*-post.log>;
if (@logfiles) {
foreach $f (@logfiles) {
print "Post test log: \t$f\n";
}
}
}
print "Mailmaster done: ", scalar(localtime), "\n"; exit 0;

View File

@@ -1,115 +0,0 @@
#!/usr/bin/perl
# The contents of this file are subject to the Netscape Public
# License Version 1.1 (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 the Netscape Mailstone utility,
# released March 17, 2000.
#
# The Initial Developer of the Original Code is Netscape
# Communications Corporation. Portions created by Netscape are
# Copyright (C) 1997-2000 Netscape Communications Corporation. All
# Rights Reserved.
#
# Contributor(s): Dan Christian <robodan@netscape.com>
# Marcel DePaolis <marcel@netcape.com>
#
# Alternatively, the contents of this file may be used under the
# terms of the GNU Public License (the "GPL"), in which case the
# provisions of the GPL are applicable instead of those above.
# If you wish to allow use of your version of this file only
# under the terms of the GPL and not to allow others to use your
# version of this file under the NPL, indicate your decision by
# deleting the provisions above and replace them with the notice
# and other provisions required by the GPL. If you do not delete
# the provisions above, a recipient may use your version of this
# file under either the NPL or the GPL.
#####################################################
# usage: perl -Ibin makeindex.pl
# Look at all the results files and create a top level index
unless ($resultbase) { # pick up systematic defaults, if needed
do 'args.pl'|| die $@;
parseArgs(); # parse command line
}
($testname = $params{WORKLOAD}) =~ s:conf/::;
$testname =~ s:.wld::;
my $entry = "";
$entry .= "<TR><TD><BR><A HREF=\"$params{TSTAMP}/results.html\">$params{TSTAMP}</A></TD>";
$entry .= "<TD>$testname</TD>\n";
$entry .= "<TD>$params{TITLE}</TD>\n";
$entry .= "<TD>$params{TIME}</TD>\n";
$entry .= "<TD>$params{CLIENTCOUNT}</TD>\n";
$entry .= "<TD><A HREF=\"$params{TSTAMP}/all.wld\">workload</A></TD>\n";
$entry .= "<TD><A HREF=\"$params{TSTAMP}/stderr\">stderr</A></TD></TR>\n";
if (-r "$resultbase/index.html") {
fileInsertAfter ("$resultbase/index.html",
"^<!-- INSERT TAGS HERE",
$entry);
} else { # create index from scratch
system ("cd $resultbase; ln -s ../doc .");
open(INDEXNEW, ">$resultbase/index.new") ||
die "Couldn't open $resultbase/index.new: $!";
print INDEXNEW <<END;
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2//EN">
<HTML>
<TITLE>
MailStone Results
</TITLE>
<HEAD>
</HEAD>
<BODY TEXT="#000000" BGCOLOR="#FFFFFF" LINK="#0000FF" VLINK="#FF0000" ALINK="#000088">
<A HREF=$mailstoneURL>Mailstone documentation</A><BR>
<TABLE BORDER=2>
<CAPTION> Netscape MailStone Results Index </CAPTION>
<TR>
<TH>Run</TH> <TH>Testname</TH> <TH> Title </TH>
<TH>Duration</TH> <TH>Clients</TH> <TH>Details</TH> <TH>Error log</TH>
</TR>
<!-- INSERT TAGS HERE - DO NOT DELETE THIS LINE -->
END
print INDEXNEW $entry; # put in this entry
# Add in any existing entries
# get a list of all the results files
@resall = <$resultbase/*/results.html>;
# Write out all the links
# This could be rather slow, but we only do it when index.html is missing
foreach $filefull (reverse @resall) {
my $file = $filefull;
$file =~ s:$resultbase/::;
if ($file eq $params{TSTAMP}) { next; } # written above
my $dir = $file;
$dir =~ s:/results.html::;
# dont read in old workloads, it will override the current one
print INDEXNEW "<TR><TD><BR><A HREF=\"$file\">$dir</A></TD>\n";
print INDEXNEW "<TD>&nbsp;</TD><TD>&nbsp;</TD><TD>&nbsp;</TD><TD>&nbsp;</TD>\n";
print INDEXNEW "<TD><A HREF=\"$dir/all.wld\">workload</A></TD>\n";
print INDEXNEW "<TD><A HREF=\"$dir/stderr\">stderr</A></TD></TR>\n";
}
print INDEXNEW <<END;
</TABLE>
</BODY>
</HTML>
END
close (INDEXNEW);
fileBackup ("$resultbase/index.html");
rename ("$resultbase/index.new", "$resultbase/index.html");
print "Created $resultbase/index.html\n";
}
return 1;

View File

@@ -1,414 +0,0 @@
#!/usr/bin/perl
# The contents of this file are subject to the Netscape Public
# License Version 1.1 (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 the Netscape Mailstone utility,
# released March 17, 2000.
#
# The Initial Developer of the Original Code is Netscape
# Communications Corporation. Portions created by Netscape are
# Copyright (C) 1997-2000 Netscape Communications Corporation. All
# Rights Reserved.
#
# Contributor(s): Dan Christian <robodan@netscape.com>
# Marcel DePaolis <marcel@netcape.com>
#
# Alternatively, the contents of this file may be used under the
# terms of the GNU Public License (the "GPL"), in which case the
# provisions of the GPL are applicable instead of those above.
# If you wish to allow use of your version of this file only
# under the terms of the GPL and not to allow others to use your
# version of this file under the NPL, indicate your decision by
# deleting the provisions above and replace them with the notice
# and other provisions required by the GPL. If you do not delete
# the provisions above, a recipient may use your version of this
# file under either the NPL or the GPL.
#####################################################
# script to create test user accounts for Netscape Messaging Server 3, 4
#
# Given a set of parameters, this script will create an LDIF file
# for a number of email users of the form:
# test1, test2, test3, ...
#
# usage: perl create_accounts_ldif [users] [broadcast] [postmaster] [ options ]
# [ -a allUsersAlias ]
# [ -b basedn ]
# [ -d maildomain ]
# [ -f firstaccount ]
# [ -k ]
# [ -m mailhost ]
# [ -n numaccounts ]
# [ -o outputfile ]
# [ -p password ]
# [ -s storebase ]
# [ -u username ]
# [ -v ]
# [ -w workload ]
# [ -x maxstores ]
# [ -3 ]
#
#perl -Ibin -- bin/makeusers.pl -d mailhost.example.com -m mailhost.example.com -b 'o=example.com' -u mailhost-test -n 100 -4 -o mailhost100.ldif
# Create the ldif for the user accounts and/or broadcast, postmaster account.
#
# The ldif then must be added to
# the directory by hand (ldapadd, or through the dir admin server's
# Database Mgmt->Add entries from an ldif file).
# A faster way
# is to export the existing directory, append the results of
# this script, and re-import the combined file. This can be
# done using the following Netscape Directory Server commands:
# stop-slapd
# db2ldif outputfile
# [ merge files ]
# ldif2db inputfile # for DS4 you would typically use -noconfig
# start-sladp
#
print "Netscape Mailstone.\nCopyright (c) 1998,1999 Netscape Communications Corp.\n";
# server to be used in the internet mail address of the users
$domain = "newdomain.example.net";
# machine that will act as the user's mailhost
$mailhost = "mailhost.example.net";
# base dn for the user entries, e.g. o=Ace Industry,c=US
$basedn = "o=Benchmark Lab, c=US";
# name of broadcast account
$bcastacct = "allusers";
# name of broadcast account
$postmasteraddr = "root\@localhost";
# base name to build user names, will construct test0, test1, ...
$username = "test%ld";
# user passwds, in SHA format, the passwd below is 'netscape'
#$userpassword = "{SHA}aluWfd0LYY9ImsJb3h4afrI4AXk=";
# these can also be imported as cleartext
$userpassword = "netscape";
# 0: no numbered passwords, 1: number with userID
$maxpass = 0;
# first account to use
$firstaccount = 0;
# number of user accounts to create ($first - $first+$num-1)
$numaccounts = 1_000;
# For larger systems, spreading the users over multiple partitions
# is usually a good idea. This example assumes you have
# created partitions named p0, p1, etc.
# store partition base name
$storebase = "p%ld";
# max store number (0 - maxstores-1), skip if 0
$maxstores = 0;
#default to msg 4 schemas
$usemsg4schema = 1;
#default to writing to stdout
$outfile = STDOUT;
# Initial UID for genpasswd
$firstuid = 1000;
sub usage {
print "Usage: perl -Ibin -- makeusers [users] [broadcast] [postmaster]\n";
print "\t[ -w workload ] [ -o outputFile ]\n";
print "\t[ -d mailDomain ] [ -m mailHost ] [ -b baseDN ]\n";
print "\t[ -u username ] [ -f firstAccount ] [ -n numAccounts ]\n";
print "\t[ -p password ] [ -k ]\n";
print "\t[ -s storeBase ] [ -x numStores ]\n";
print "\t[ -a allUsersAlias ] [ -t postmasterAddress ]\n";
print "\t[ -3 ]|[ -4 ]\n";
}
sub readWorkConfig { # read the workload in, parse our params
my $workloadfile = shift || die "Workload file name expected\n";
do 'args.pl'|| die $@;
readWorkloadFile ($workloadfile, \@workload)
|| die "Error reading workload: $@\n";
# assign all the parameters from the config
$mailhost = $defaultSection->{SERVER}
if ($defaultSection->{SERVER});
if ($defaultSection->{ADDRESSFORMAT}) {
my $addr = $defaultSection->{ADDRESSFORMAT};
$addr =~ s/^.*@//;
$domain = $addr;
}
if ($defaultSection->{LOGINFORMAT}) {
my $user = $defaultSection->{LOGINFORMAT};
#$user =~ s/%ld$//;
$username = $user;
}
$numaccounts = $defaultSection->{NUMLOGINS}
if ($defaultSection->{NUMLOGINS});
$firstaccount = $defaultSection->{FIRSTLOGINS}
if ($defaultSection->{FIRSTLOGINS});
$userpassword = $defaultSection->{PASSWDFORMAT}
if ($defaultSection->{SERVER});
if ($userpassword =~ m/%ld/) { # see if numbered passwords
$maxpass++;
#$userpassword =~ s/%ld//g;
}
# what isnt set: basedn, storebase, maxstores, usemsg4schema
}
while (@ARGV) {
$arg = shift(@ARGV);
if ($arg =~ /^-a$/i) { # allusers (broadcast) user name
$bcastacct = shift(@ARGV);
next;
}
if ($arg =~ /^-b$/i) { # LDAP base DN
$basedn = shift(@ARGV);
next;
}
if ($arg =~ /^-d$/i) { # mail domain
$domain = shift(@ARGV);
next;
}
if ($arg =~ /^-f$/i) { # initial account
$firstaccount = shift(@ARGV);
next;
}
if ($arg =~ /^-k$/i) { # use numbered passwords
$maxpass++;
next;
}
if ($arg =~ /^-h$/i) { # help
usage();
exit 0;
}
if ($arg =~ /^-m$/i) { # mail server name
$mailhost = shift(@ARGV);
next;
}
if ($arg =~ /^-n$/i) { # number of accounts
$numaccounts = shift(@ARGV);
next;
}
if ($arg =~ /^-o$/i) { # name output file
my $fname = shift || die "File name expected\n";
open OUTFILE, ">$fname" || die "Error opening file $@\n";
$outfile = OUTFILE;
next; # use msg4 user admin schema
}
if ($arg =~ /^-p$/i) { # password
$userpassword = shift(@ARGV);
next;
}
if ($arg =~ /^-s$/i) { # base name for above
$storebase = shift(@ARGV);
next;
}
if ($arg =~ /^-t$/i) { # postmaster address
$postmasteraddress = shift(@ARGV);
next;
}
if ($arg =~ /^-u$/i) { # user name base
$username = shift(@ARGV);
next;
}
if ($arg =~ /^-v$/i) { # be verbose
$verbose++;
next;
}
# do this when read, so that later switches can override
if ($arg =~ /^-w$/i) { # get a workload file
readWorkConfig (shift(@ARGV));
next;
}
if ($arg =~ /^-x$/i) { # number of partitions (0 to skip)
$maxstores = shift(@ARGV);
next;
}
if ($arg =~ /^-3$/) { # no msg4 schema
$usemsg4schema = 0;
next;
}
if ($arg =~ /^-4$/) { # use msg4 user admin schema
$usemsg4schema = 1;
next;
}
if ($arg =~ /^users$/i) {
$genusers++;
next;
}
if ($arg =~ /^broadcast$/i) {
$genbroadcast++;
next;
}
if ($arg =~ /^passwd$/i) {
$genpasswd++;
next;
}
if ($arg =~ /^postmaster$/i) {
$genpostmaster++;
next;
}
print STDERR "Unknown argument $arg. Use -h for help.\n";
exit 1;
}
unless (($genusers) || ($genbroadcast) || ($genpasswd) || ($genpostmaster)) {
print STDERR "Must specify mode [users] [broadcast] [postmaster] ...\n";
usage();
exit 0;
}
# specify number fields, if needed
unless ($username =~ /%ld/) {
$username .= '%ld';
}
if (($maxpass) && !($userpassword =~ /%ld/)) {
$userpassword .= '%ld';
}
if (($maxstores) && !($storename =~ /%ld/)) {
$storename .= '%ld';
}
if ($verbose) {
print STDERR "Here is the configuration:\n";
print STDERR "baseDN='$basedn' \t";
print STDERR (($usemsg4schema) ? "-4\n" : "-3\n");
print STDERR "mailHost='$mailhost' \tdomain='$domain'\n";
print STDERR "userName='$username' \tnumAccounts=$numaccounts \tfirstAccount=$firstaccount\n";
print STDERR "userPassword='$userpassword'\n";
print STDERR "allUsersAccount='$bcastacct'\n" if ($genbroadcast);
print STDERR "postmasterAddress='$postmasterAddress'\n" if ($genpostmaster);
}
if ($genusers) { # Create the user accounts
$storenum=0;
for ($i = $firstaccount; $i < $firstaccount+$numaccounts; $i++) {
# build user account name
my $acctname = $username;
$acctname =~ s/%ld/$i/; # insert user number
my $password = $userpassword;
$password =~ s/%ld/$i/; # insert user number
# MAKE SURE THERE ARE NO TRAILING SPACES IN THE LDIF
my $extradata = "";
if ($maxstores > 0) { # assign them to a store
my $storename = $storebase;
$storename =~ s/%ld/$storenum/;
$extradata .= "mailmessagestore: $storename\n";
$storenum++;
$storenum=0 if ($storenum >= $maxstores);
}
$extradata .= "objectclass: nsMessagingServerUser\n"
if ($usemsg4schema);
print $outfile <<END;
dn: uid=$acctname, $basedn
userpassword: $password
givenname: $acctname
sn: $acctname
cn: $acctname
uid: $acctname
mail: $acctname\@$domain
mailhost: $mailhost
maildeliveryoption: mailbox
objectclass: top
objectclass: person
objectclass: organizationalPerson
objectclass: inetOrgPerson
objectclass: mailRecipient
$extradata
END
}
}
if ($genbroadcast) { # Create the broadcast account
# MAKE SURE THERE ARE NO TRAILING SPACES IN THE LDIF
my $password = $userpassword;
$password =~ s/%ld//; # strip user number
# initial part
print $outfile <<END;
dn: uid=$bcastacct, $basedn
userpassword: $password
givenname: $bcastacct
sn: $bcastacct
cn: $bcastacct
uid: $bcastacct
mail: $bcastacct\@$domain
mailhost: $mailhost
maildeliveryoption: forward
END
# now put in each address
for ($i = $firstaccount; $i < $firstaccount+$numaccounts; $i++) {
# build user account name
my $acctname = $username;
$acctname =~ s/%ld/$i/; # insert user number
print $outfile "mailforwardingaddress: $acctname\@$domain\n";
}
# final part
print $outfile <<END;
objectclass: top
objectclass: person
objectclass: organizationalPerson
objectclass: inetOrgPerson
objectclass: mailRecipient
END
}
if ($genpostmaster) { # Create the postmaster account
# MAKE SURE THERE ARE NO TRAILING SPACES IN THE LDIF
print $outfile <<END;
dn: cn=postmaster, $basedn
cn: postmaster
mail: postmaster\@$domain
mailalternateaddress: postmaster\@$mailhost
mgrprfc822mailmember: $postmasterAddress
objectclass: top
objectclass: mailGroup
objectclass: groupOfUniqueNames
END
}
# mixing passwd output with the ldif output above would be quite silly
if ($genpasswd) { # Create passwd entries for makeusers
for ($i = $firstaccount; $i < $firstaccount+$numaccounts; $i++) {
# build user account name
my $acctname = $username;
$acctname =~ s/%ld/$i/; # insert user number
my $password = $userpassword;
$password =~ s/%ld/$i/; # insert user number
my $uid = $firstuid + $i;
print $outfile "$acctname:$password:$uid:$uid:Mail user $acctname:/home/$acctname:/bin/sh\n";
}
}
exit 0;

View File

@@ -1,371 +0,0 @@
#!/usr/bin/perl
# The contents of this file are subject to the Netscape Public
# License Version 1.1 (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 the Netscape Mailstone utility,
# released March 17, 2000.
#
# The Initial Developer of the Original Code is Netscape
# Communications Corporation. Portions created by Netscape are
# Copyright (C) 1997-2000 Netscape Communications Corporation. All
# Rights Reserved.
#
# Contributor(s): Dan Christian <robodan@netscape.com>
# Marcel DePaolis <marcel@netcape.com>
#
# Alternatively, the contents of this file may be used under the
# terms of the GNU Public License (the "GPL"), in which case the
# provisions of the GPL are applicable instead of those above.
# If you wish to allow use of your version of this file only
# under the terms of the GPL and not to allow others to use your
# version of this file under the NPL, indicate your decision by
# deleting the provisions above and replace them with the notice
# and other provisions required by the GPL. If you do not delete
# the provisions above, a recipient may use your version of this
# file under either the NPL or the GPL.
#####################################################
# Generate reports independently of mailmaster
# Can be used during a run or after mailmaster has finished
print "Netscape Mailstone\n";
print "Copyright (c) 1997-2000 Netscape Communications Corp.\n";
# this parses the command line and config file
do 'args.pl'|| die $@;
parseArgs(); # parse command line
setConfigDefaults(); # pick up any missing defaults
$resultdir = "$resultbase/$params{TSTAMP}";
$tmpdir = "$tmpbase/$params{TSTAMP}";
$resultstxt = "$resultdir/results.txt";
$resultshtml = "$resultdir/results.html";
if ($params{TESTBED}) { # BACK COMPATIBILITY
$params{TESTBED} = "$resultdir/testbed.tbd"; # use saved testbed
# open the saved testbed conf file
readTestbedFile($params{TESTBED}) || die "$@\n";
}
# Convert old style to new. Write the complete inclusive workload
writeWorkloadFile ("$resultdir/all.wld", \@workload)
unless ((-r "$resultdir/all.wld") || (-r "$resultdir/all.wld.gz"));
$testsecs = figureTimeSeconds ($params{TIME}, "minutes");
print "Starting data reduction\n";
sub readClientCSV {
my $file = shift;
my @fields;
my $line;
print "Reading client summary: $file\n";
open(CSV, "<$file") || # Summary of all clients
open(CSV, "gunzip -c $file.gz |") ||
return 0; # failed
# Title line: Verify that arguments are in the same order
$line = <CSV>;
unless ($line) {
print "readClientCSV: Error reading $file. \n";
return 0;
}
chomp $line; # strip newline
@fields = split /,/, $line; # turn into an array
my $cli = shift @fields; # pull off client header
my $cn = shift @fields; # pull off num header
my $pro = shift @fields; # pull off protocol header
# Client array, per variable, per protocol
foreach $p (@protocols) {
# This hash will hold the timers
$clidata{$p} = ArrayInstance->new();
foreach $t (@timers) {
# This hash will hold the values in the timer
$clidata{$p}->{$t} = ArrayInstance->new();
foreach $f (@{$timerFields{$t}}) {
# This hash that will hold the actual values per client
$clidata{$p}->{$t}->{$f} = ArrayInstance->new();
}
}
foreach $t (@scalarClientFields) { # non-timer fields
# This hash that will hold the actual values per client
$clidata{$p}->{$t} = ArrayInstance->new();
}
}
foreach $f (@commClientFields) { # proto independent
my $v = shift @fields;
if ($v !~ m/$f/i) {
print "readClientCSV: Protocol order mismatch '$v', '$f' \n";
return 0;
}
}
foreach $t (@timers) { # timers
foreach $f (@{$timerFields{$t}}) {
my $v = shift @fields;
if ($v !~ m/$t:$f/i) {
print "readClientCSV: Protocol order mismatch '$v', '$t:$f' \n";
return 0;
}
}
}
foreach $t (@scalarClientFields) { # scalars
my $v = shift @fields;
if ($v !~ m/$t/i) {
print "readClientCSV: Protocol order mismatch '$v', '$t' \n";
return 0;
}
}
# Now read actual data
while (<CSV>) {
chomp; # strip newline
@fields = split /,/; # turn into an array
my $cli = shift @fields; # pull off client header
my $cn = shift @fields; # pull off num header
my $p = shift @fields; # pull off protocol header
my $cp = $clidata{$p};
# Create the needed finals arrays
unless ($finals{$p}) {
#print "Creating finals{$p}\n"; # DEBUG
$finals{$p} = ArrayInstance->new();
foreach $t (@timers) {
$finals{$p}->{$t} = ArrayInstance->new();
}
}
foreach $f (@commClientFields) { # proto independent
$cliGen{$f}->{$cn} = shift @fields;
}
foreach $t (@timers) { # timers
foreach $f (@{$timerFields{$t}}) {
$cp->{$t}->{$f}->{$cn} = shift @fields;
$finals{$p}->{$t}->{$f} += $cp->{$t}->{$f}->{$cn};
}
}
foreach $t (@scalarClientFields) { # scalars
$cp->{$t}->{$cn} = shift @fields;
$finals{$p}->{$t} += $cp->{$t}->{$cn};
}
foreach $section (@workload) { # find thread count for this client
next unless ($section->{sectionTitle} =~ /CLIENT/o);
next unless ($section->{sectionParams} =~ /$cli/);
#print "Process $cli has threads $section->{THREADS}\n";
$reportingClients += ($section->{THREADS})
? $section->{THREADS} : 1;
last;
}
}
close (CSV);
return 1; # success
}
sub readTimeCSV {
my $file = shift;
my $p = shift;
my $gp = $graphs{$p};
my $line;
print "Reading time $p summary: $file\n";
open(CSV, "<$file") || # Summary over time
open(CSV, "gunzip -c $file.gz |") ||
return 0; # failed
# Verify that arguments are in the same order
$line = <CSV>;
unless ($line) {
print "readTimeCSV: Error reading $file. \n";
return 0;
}
chomp $line; # strip newline
@fields = split /,/, $line;
my $t = shift @fields; # pull off time header
foreach $t (@timers) {
foreach $f (@{$timerFields{$t}}) {
my $v = shift @fields;
if ($v !~ m/$t:$f/i) {
print "readTimeCSV: Protocol order mismatch '$v', '$t:$f' \n";
return 0;
}
}
}
foreach $t (@scalarGraphFields) {
my $v = shift @fields;
if ($v !~ m/$t/i) {
print "readTimeCSV: Protocol order mismatch '$v', '$t' \n";
return 0;
}
}
while (<CSV>) {
chomp;
#print "LINE: $_\n";
@fields = split /,/;
my $tm = shift @fields; # pull off time header
#print "t=$t ";
foreach $t (@timers) {
foreach $f (@{$timerFields{$t}}) {
$gp->{$t}->{$f}->{$tm} = shift @fields;
#print "$v=$gp->{$v}->{$tm} ";
}
}
foreach $t (@scalarGraphFields) {
$gp->{$t}->{$tm} = shift @fields;
#print "$v=$gp->{$v}->{$tm} ";
}
#print "\n";
}
close (CSV);
return 1; # success
}
sub loadCSV {
my @csvs = <$resultdir/time-*.csv>;
@csvs = <$resultdir/time-*.csv.gz> unless (@csvs);
return 0 unless (@csvs); # no time.csv files
# stuff normally done from reduce.pl (should all be in protoconf?)
# Basic sanity check
return 0 unless ($testsecs > 0);
$startTime = 0; # these are timeInSeconds/$timeStep
$endTime = 0;
# keep graphs with somewhat more precision than sample rate;
$timeStep = int ($params{FREQUENCY} / 2);
if ($timeStep < 1) { $timeStep = 1; }
# global results initialization
$reportingClients = 0;
$totalProcs = 0; # number of clients started
foreach $f (@commClientFields) { # protocol independent fields
$cliGen{$f} = ArrayInstance->new();
}
return 0 unless (readClientCSV ("$resultdir/clients.csv")); # client info
foreach $c (@csvs) { # read time info
$c =~ s/.gz$//; # strip .gz extension
my $p = $c; # strip down to protocol portion
$p =~ s/$resultdir\/time-//;
$p =~ s/.csv$//;
return 0 unless (readTimeCSV ($c, $p));
}
return 0 unless ($reportingClients > 0);
foreach $section (@workload) {
next unless ($section->{sectionTitle} =~ /CLIENT/o);
my $slist = $section->{sectionParams};
$slist =~ s/HOSTS=\s*//; # strip off initial bit
my @hlist = split /[\s,]/, $slist;
my $hcnt = (1 + $#hlist);
my $pcount = $section->{PROCESSES};
my $tcount = ($section->{THREADS}) ? $section->{THREADS} : 1;
$totalProcs += $pcount * $tcount * $hcnt;
}
# Find time extent for a key graph
($startTime, $endTime) = dataMinMax ("blocks", \@protocols,
$startTime, $endTime);
$realTestSecs = ($endTime - $startTime) * $timeStep;
$realTestSecs = 1 unless ($realTestSecs); # in case of small MaxBlocks
printf "Reported test duration %d seconds with %d second resolution\n",
$realTestSecs, $timeStep;
$realTestSecs = $testsecs if ($realTestSecs > $testsecs);
my @newProtos; # figure real protocol list
foreach $p (@protocols) {
my $gp = $graphs{$p};
my $numValid = 0;
# See if there is real data here
CHECKVAL: foreach $t (@timers) {
foreach $f (@{$timerFields{$t}}) {
my $vp = $gp->{$t}->{$f};
next unless ($vp); # no data
next unless (scalar %$vp); # redundant???
#print "Checking: $p $t $f => ENTRIES\n";
$numValid++;
last CHECKVAL;
}
}
($numValid > 0) || next;
push @newProtos, $p;
}
# update protocol list to only have what was used
@protocols = @newProtos;
@protocolsAll = @newProtos;
push @protocolsAll, "Total";
}
my $doFull = 1; # re-processing is currently broken
# if (!((-f "$resultdir/clients.csv")
# || (-f "$resultdir/clients.csv.gz"))) { # no processing yet
# $doFull = 1;
# } else { # see if any source is newer than csv
# foreach $section (@workload) {
# next unless ($section->{sectionTitle} =~ /CLIENT/o);
# my $slist = $section->{sectionParams};
# $slist =~ s/HOSTS=\s*//; # strip off initial bit
# foreach $cli (split /[\s,]/, $slist) {
# my $fname = getClientFilename ($cli, $section);
# if ((-r $fname) # raw source exists
# && ((-M "$resultdir/clients.csv")
# > (-M $fname))) { # newer
# #print "$fname is newer than $resultdir/clients.csv\n";
# $doFull++;
# last;
# }
# }
# }
# }
# unless ($doFull) { # do CSV load
# # if this is a csv only run, then these may not exist yet
# mkdir ("$tmpbase", 0775);
# mkdir ("$tmpdir", 0775);
# unless (-r "$resultbase/index.html") {
# do 'makeindex.pl' || warn "$@\n"; # html index
# }
# $doFull = 1 unless (loadCSV); # if CSV fails, fall back to full processing
# }
if ($doFull) {
do 'reduce.pl' || die "$@\n";
}
print "Generating results pages:\t", scalar (localtime), "\n";
do 'report.pl' || die "$@\n";
# Now display that data to console
if ($params{VERBOSE}) {
fileShow ($resultstxt);
print "\n";
}
pathprint ("\nResults (text):\t$resultstxt\n");
pathprint ( "Results (HTML):\t$resultshtml\n");
print "Index of runs: \tfile://$cwd/$resultbase/index.html\n";
print "Process done:\t", scalar (localtime), "\n";

View File

@@ -1,158 +0,0 @@
# The contents of this file are subject to the Netscape Public
# License Version 1.1 (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 the Netscape Mailstone utility,
# released March 17, 2000.
#
# The Initial Developer of the Original Code is Netscape
# Communications Corporation. Portions created by Netscape are
# Copyright (C) 1997-2000 Netscape Communications Corporation. All
# Rights Reserved.
#
# Contributor(s): Dan Christian <robodan@netscape.com>
# Marcel DePaolis <marcel@netcape.com>
#
# Alternatively, the contents of this file may be used under the
# terms of the GNU Public License (the "GPL"), in which case the
# provisions of the GPL are applicable instead of those above.
# If you wish to allow use of your version of this file only
# under the terms of the GPL and not to allow others to use your
# version of this file under the NPL, indicate your decision by
# deleting the provisions above and replace them with the notice
# and other provisions required by the GPL. If you do not delete
# the provisions above, a recipient may use your version of this
# file under either the NPL or the GPL.
#####################################################
# This define the structures that hold summary, client, and graph data,
# This sets the names used for display. Can be internationalized.
# All top level names are here (both timers and scalars).
# Any unlisted names will map to themselves.
%timerNames
= (
#internal name, Printed name
"total", "total",
"conn", "connect",
"reconn", "reconnect",
"banner", "banner",
"login", "login",
"cmd", "command",
"submit", "submit",
"retrieve", "retrieve",
"logout", "logout",
"idle", "idle",
"connections", "connections",
"blocks", "blocks",
);
# This sets the names used for display. Can be internationalized.
%fieldNames
= (
#internal name, Printed name
"Try", "Try",
"Error", "Error",
"BytesR", "BytesR",
"BytesW", "BytesW",
"Time", "Time",
"TimeMin", "TMin",
"TimeMax", "TMax",
"Time2", "TStd",
);
# hold time graphs for each protocol
%graphs = ();
# Totals are done during plotting, if needed
%finals = (); # create base finals hash
# These are sections that dont get passed to mailclient (case insensitive)
@scriptWorkloadSections
= (
"Config", # special, references %params
"Client", # testbed client(s)
"Graph", # graph generation
"Setup", # things to run with ./setup
"Startup", # things to run before test
"Monitor", # other performance monitoring
"PreTest", # things to run before test
"PostTest", # things to run after test
);
# These are sections that arent protocols. Anything else must be.
@nonProtocolSections
= (@scriptWorkloadSections, ("Default"));
# These are the known workload parameters (as they will print)
# These are coerced to upper case internally (do NOT internationize)
@workloadParameters
= (
"addressFormat",
"arch",
"blockID",
"blockTime",
"chartHeight",
"chartPoints",
"chartWidth",
"clientCount",
"command",
"comments",
"file",
"firstAddress",
"firstLogin",
"frequency",
"gnuplot",
"group",
"idleTime",
"leaveMailOnServer",
"loginFormat",
"loopDelay",
"numAddresses",
"numLogins",
"numLoops",
"numRecips",
"mailClient",
"maxBlocks",
"maxClients",
"maxErrors",
"maxThreads",
"maxProcesses",
"passwdFormat",
"processes",
"rampTime",
"rcp",
"rsh",
"sequentialAddresses",
"sequentialLogins",
"server",
"smtpMailFrom",
"sysConfig",
"threads",
"telemetry",
"tempDir",
"time",
"title",
"TStamp",
"useAuthLogin",
"useEHLO",
"weight",
"wmapBannerCmds",
"wmapClientHeader",
"wmapInBoxCmds",
"wmapLoginCmd",
"wmapLoginData",
"wmapLogoutCmds",
"wmapMsgReadCmds",
"wmapMsgWriteCmds",
"workload",
);
return 1;

File diff suppressed because it is too large Load Diff

View File

@@ -1,605 +0,0 @@
# The contents of this file are subject to the Netscape Public
# License Version 1.1 (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 the Netscape Mailstone utility,
# released March 17, 2000.
#
# The Initial Developer of the Original Code is Netscape
# Communications Corporation. Portions created by Netscape are
# Copyright (C) 1997-2000 Netscape Communications Corporation. All
# Rights Reserved.
#
# Contributor(s): Dan Christian <robodan@netscape.com>
# Marcel DePaolis <marcel@netcape.com>
#
# Alternatively, the contents of this file may be used under the
# terms of the GNU Public License (the "GPL"), in which case the
# provisions of the GPL are applicable instead of those above.
# If you wish to allow use of your version of this file only
# under the terms of the GPL and not to allow others to use your
# version of this file under the NPL, indicate your decision by
# deleting the provisions above and replace them with the notice
# and other provisions required by the GPL. If you do not delete
# the provisions above, a recipient may use your version of this
# file under either the NPL or the GPL.
#####################################################
# This file deals with the summary data only
# Should be packages
do 'genplot.pl' || die "$@\n";
sub walkSetupTotals {
my $a = shift; my $f = shift; my $p = shift;
if ($p =~ /(\w+):(\w+):$/) {
my $tm = $2;
if (!($finals{Total}->{$tm}->{$f})) {
$finals{Total}->{$tm}->{$f} = $a;
} elsif ($f =~ /Min$/) {
$finals{Total}->{$tm}->{$f} = $a
if (($a > 0.0) && ($a < $finals{Total}->{$tm}->{$f}));
} elsif ($f =~ /Max$/) {
$finals{Total}->{$tm}->{$f} = $a if ($a > $finals{Total}->{$tm}->{$f});
} else {
$finals{Total}->{$tm}->{$f} += $a;}
}
elsif ($p =~ /(\w+):$/) {
$finals{Total}->{$f} += $a;
}
}
sub setupTotals {
# Figure out combined timers for "Total" protocol
# We might do a smarter merge here (look at context and try to match order)
# As long as the first protocol is a superset, it wont matter
my @tnames;
foreach $proto (@protocols) {
foreach $n (@{$protocolFields{$proto}}) {
my $t = $n;
$t =~ s/([][{}*+?^.\/])/\\$1/g; # quote regex syntax
my $found = 0;
foreach $tn (@tnames) { # see if it is in the list already
next unless ($tn =~ /$t/);
$found = 1;
last;
}
#print "proto $proto: Found $n\n" if ($found > 0);
next if ($found > 0);
#print "proto $proto: Add $n\n";
push @tnames, $n; # add to list
}
}
#print "'Total' timers @tnames\n";
$protocolFields{"Total"} = \@tnames;
# Create "Total" hashes
$finals{Total} = ArrayInstance->new();
foreach $n (@{$protocolFields{"Total"}}) { # all timers
my $t = $n; # dont modify original list
if ($t =~ /^\[(\w+)\]$/) { # Timer case, strip off brackets
$finals{Total}->{$1} = ArrayInstance->new();
#print "Creating Total timer field $1\n";
} else { # scalar
$finals{Total}->{$n} = 0;
#print "Creating Total scalar field $n\n";
}
}
# Total finals array
foreach $proto (@protocols) {
foreach $t (@{$protocolFields{$proto}}) {
if ($t =~ /^\[(\w+)\]$/) { # Timer case, strip off brackets
my $tm = $1;
foreach $f (@timerFieldsAll) {
my $a = $finals{$proto}->{$tm}->{$f};
if (!($finals{Total}->{$tm}->{$f})) { # never touched
$finals{Total}->{$tm}->{$f} = $a;
} elsif ($f =~ /Min$/) {
$finals{Total}->{$tm}->{$f} = $a
if (($a > 0.0)
&& ($a < $finals{Total}->{$tm}->{$f}));
} elsif ($f =~ /Max$/) {
$finals{Total}->{$tm}->{$f} = $a
if ($a > $finals{Total}->{$tm}->{$f});
} else {
$finals{Total}->{$tm}->{$f} += $a;
}
}
} else {
$finals{Total}->{$t} += $finals{$proto}->{$t};
}
}
}
# Convert Time2 to standard deviation
foreach $proto (@protocolsAll) {
foreach $n (@{$protocolFields{$proto}}) {
my $t = $n; # dont modify original list
if ($t =~ /^\[(\w+)\]$/) { $t = $1; } # strip off brackets
next unless ($finals{$proto}->{$t}); # proto doesnt have timer
next unless ($finals{$proto}->{$t}->{Try});
next unless ($finals{$proto}->{$t}->{Time2} > 0);
my $ss = $finals{$proto}->{$t}->{Time2};
my $tot = $finals{$proto}->{$t}->{Time};
my $n = $finals{$proto}->{$t}->{Try};
next unless ($n > 0); # skip if this is 0
my $var = ($ss - (($tot * $tot) / $n)) / $n;
print "$proto->$t var < 0: Time2=$ss Time=$tot n=$n\n"
if ($var < 0);
$finals{$proto}->{$t}->{Time2} = ($var > 0) ? sqrt ($var) : 0.0;
}
}
# Divide total times by trys to get averate time
foreach $proto (@protocolsAll) {
foreach $n (@{$protocolFields{$proto}}) {
my $t = $n; # dont modify original list
if ($t =~ /^\[(\w+)\]$/) { $t = $1; } # strip off brackets
next unless ($finals{$proto}->{$t}); # proto doesnt have timer
($finals{$proto}->{$t}->{Try}) || next;
$finals{$proto}->{$t}->{Time} /= $finals{$proto}->{$t}->{Try}
}
}
}
# The text version is designed to be machine processable
# commify and kformat are not used
sub genTextReport {
fileBackup ($resultstxt); # if processing as we go, backup old file
# Open a text file to hold the results
open(RESULTSTXT, ">$resultstxt") ||
die "Couldn't open $resultstxt: $!";
# Store results as text
printf RESULTSTXT "---- Netscape MailStone Results $params{TSTAMP} ----\n";
printf RESULTSTXT "\t\t%s\n", $params{TITLE};
printf RESULTSTXT "\t\t%s\n", $params{COMMENTS};
printf RESULTSTXT "\n";
printf RESULTSTXT "Test duration: %d %s. Rampup: %d %s. Reported duration %s seconds\n",
figureTimeNumber ($params{TIME}),
figureTimeUnits ($params{TIME}, "minutes"),
figureTimeNumber ($params{RAMPTIME}),
figureTimeUnits ($params{RAMPTIME}, "seconds"), $realTestSecs;
printf RESULTSTXT "Number of reporting clients: %s of %s\n",
$reportingClients, $totalProcs;
foreach $proto (@protocolsAll) {
# do op counters
printf RESULTSTXT "\n%-15s ", $proto;
foreach $f (@timerFieldsAll) {
#($f =~ m/^Time2$/o) && next;
printf RESULTSTXT "%13s",
($fieldNames{$f}) ? $fieldNames{$f} : $f;
}
foreach $n (@{$protocolFields{$proto}}) {
my $t = $n; # dont modify original list
unless ($t =~ /^\[(\w+)\]$/) { # scalar case
#next; # skip scalars for now
# do scalar counters. Column should line up with "Try"
printf RESULTSTXT "\n%-15s ",
$proto . ":" . (($timerNames{$t}) ? $timerNames{$t} : $t);
printf RESULTSTXT
"%13s", $finals{$proto}->{$t};
next;
} else { # strip off brackets
$t = $1;
}
printf RESULTSTXT "\n%-15s ",
$proto . ":" . (($timerNames{$t}) ? $timerNames{$t} : $t);
foreach $f (@timerFieldsAll) {
#($f =~ m/^Time2$/o) && next;
if ($f =~ m/Time/o) {
printf RESULTSTXT
"%13.3f", $finals{$proto}->{$t}->{$f};
} elsif ($f =~ m/Bytes/o) {
printf RESULTSTXT
"%13d", $finals{$proto}->{$t}->{$f};
} else {
printf RESULTSTXT
"%13s", $finals{$proto}->{$t}->{$f};
}
}
}
# do ops/sec
printf RESULTSTXT "\n\n%-15s ", $proto;
foreach $f (@timerFieldsAll) {
($f =~ m/^Time/o) && next;
printf RESULTSTXT "%9s/sec",
($fieldNames{$f}) ? $fieldNames{$f} : $f;
}
foreach $n (@{$protocolFields{$proto}}) {
my $t = $n; # dont modify original list
unless ($t =~ /^\[(\w+)\]$/) { # scalar case
#next; # skip scalars for now
# do scalar counter/sec. Column should line up with "Try"
printf RESULTSTXT "\n%-15s ",
$proto . ":" . (($timerNames{$t}) ? $timerNames{$t} : $t) . "/s";
printf RESULTSTXT
"%13.3f", $finals{$proto}->{$t} / $realTestSecs;
next;
} else {
$t = $1;
}
printf RESULTSTXT "\n%-15s ",
$proto . ":" . (($timerNames{$t}) ? $timerNames{$t} : $t) . "/s";
foreach $f (@timerFieldsAll) {
($f =~ m/^Time/o) && next;
if ($f =~ m/Bytes/o) {
printf RESULTSTXT
"%13d",
$finals{$proto}->{$t}->{$f} / $realTestSecs;
} else {
printf RESULTSTXT
"%13.3f",
$finals{$proto}->{$t}->{$f} / $realTestSecs;
}
}
}
printf RESULTSTXT "\n\n";
}
if ($params{SYSCONFIG}) {
print RESULTSTXT "\nSytem config details\n";
if (($params{SYSCONFIG} =~ m/^\S+$/o)
&& (open(SCFILE, "<$params{SYSCONFIG}"))) {
while (<SCFILE>) {
(m/^<\S+>\s*$/o) && next; # skip HTML only on them
s/<\S+>//g; # trim out obvious HTML commands
s/<!--.*-->//g; # trim out HTML comments
print RESULTSTXT $_;
}
close(SCFILE);
} else {
my $l = $params{SYSCONFIG}; # filter similar to above
$l =~ s/<\S+>//g; # trim out obvious HTML commands
$l =~ s/<!--.*-->//g; # trim out HTML comments
$l =~ s/\\\n/\n/g; # turn quoted newline to plain newline
print RESULTSTXT $l;
}
}
close(RESULTSTXT);
}
# Write the main part of the HTML page
sub genHTMLReportStart {
fileBackup ($resultshtml); # if processing as we go, backup old file
# Open an html file to hold the results
open(RESULTSHTML, ">$resultshtml") ||
die "Couldn't open $resultshtml: $!";
print RESULTSHTML <<END;
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2//EN">
<HTML>
<A NAME=TitleSection>
<TITLE>
Netscape MailStone Results $params{TSTAMP}
</TITLE>
</A>
<HEAD>
</HEAD>
<BODY TEXT="#000000" BGCOLOR="#FFFFFF" LINK="#0000FF" VLINK="#FF0000" ALINK="#000088">
<CENTER>
<HR NOSHADE WIDTH="100%">
<H1>Netscape MailStone Results $params{TSTAMP}</H1>
<H2>$params{TITLE}</H2>
<I>$params{COMMENTS}</I>
<HR WIDTH="100%">
</CENTER>
END
printf RESULTSHTML "<BR><B>Test duration:</B> %d %s. ",
figureTimeNumber ($params{TIME}),
figureTimeUnits ($params{TIME}, "minutes");
printf RESULTSHTML "<B>Rampup:</B> %d %s. ",
figureTimeNumber ($params{RAMPTIME}),
figureTimeUnits ($params{RAMPTIME}, "seconds");
printf RESULTSHTML "<B>Reported duration:</B> %s seconds\n",
commify ($realTestSecs);
printf RESULTSHTML "<BR><B>Reporting clients:</B> %s of %s\n",
commify ($reportingClients), commify ($totalProcs);
print RESULTSHTML <<END;
<BR>
Test <A HREF="all.wld">complete workload</a> description.
Filtered <A HREF="work.wld">workload</a> description.
<BR>
Plain <A HREF="results.txt">text version</a> of results.
Log of <A HREF="stderr">stderr</a> and debugging output.
<BR>
<A NAME=MonitoringSection></A>
END
{ # list user requested logging
my @logfiles = <$resultdir/*-pre.log>;
if (@logfiles) {
foreach $f (@logfiles) {
$f =~ s/$resultdir\///o; # strip directory out
$f =~ s/-pre\.log$//o; # strip extension off
print RESULTSHTML "Pre test log: <A HREF=\"$f-pre.log\">$f</a><BR>\n";
}
}
@logfiles = <$resultdir/*-run.log>;
if (@logfiles) {
foreach $f (@logfiles) {
$f =~ s/$resultdir\///o; # strip directory out
$f =~ s/-run\.log$//o; # strip extension off
print RESULTSHTML "Monitoring log: <A HREF=\"$f-run.log\">$f</a><BR>\n";
}
}
@logfiles = <$resultdir/*-post.log>;
if (@logfiles) {
foreach $f (@logfiles) {
$f =~ s/$resultdir\///o; # strip directory out
$f =~ s/-post\.log$//o; # strip extension off
print RESULTSHTML "Post test log: <A HREF=\"$f-post.log\">$f</a><BR>\n";
}
}
}
#print RESULTSHTML
#"<CENTER><H2>Results per protocol</H2></CENTER>\n";
foreach $proto (@protocolsAll) {
printf RESULTSHTML "<A NAME=%sTable></A>\n", $proto;
printf RESULTSHTML
"<TABLE BORDER=2 CELLSPACING=2 CELLPADDING=2 COLS=%d WIDTH=\"95%%\">",
2+$#{@{$protocolFields{$proto}}};
print RESULTSHTML
"<CAPTION>$proto Counters</CAPTION>\n";
# do op counters
print RESULTSHTML
"<TR><TH>$proto</TH>\n";
foreach $f (@timerFieldsAll) {
#($f =~ m/^Time2$/o) && next;
printf RESULTSHTML "<TH>%s</TH> ",
($fieldNames{$f}) ? $fieldNames{$f} : $f;
}
print RESULTSHTML
"</TR>\n";
foreach $n (@{$protocolFields{$proto}}) {
my $t = $n; # dont modify original list
unless ($t =~ /^\[(\w+)\]$/) { # scalar case
next; # skip scalars for now
# do scalar counters. Column should line up with "Try"
printf RESULTSHTML "<TR ALIGN=RIGHT><TH>%s</TH>\n",
($timerNames{$t}) ? $timerNames{$t} : $t;
printf RESULTSHTML
"<TD>%s</TD> ",
commify ($finals{$proto}->{$t});
next;
} else {
$t = $1;
}
printf RESULTSHTML "<TR ALIGN=RIGHT><TH>%s</TH>\n",
($timerNames{$t}) ? $timerNames{$t} : $t;
foreach $f (@timerFieldsAll) {
#($f =~ m/^Time2$/o) && next;
if ($f =~ m/Time/o) {
printf RESULTSHTML
"<TD>%s</TD> ",
tformat ($finals{$proto}->{$t}->{$f});
} elsif ($f =~ m/Bytes/o) {
printf RESULTSHTML
"<TD>%s</TD> ",
kformat ($finals{$proto}->{$t}->{$f});
} else {
printf RESULTSHTML
"<TD>%s</TD> ",
commify ($finals{$proto}->{$t}->{$f});
}
}
print RESULTSHTML "</TR>\n";
}
# do ops/sec
print RESULTSHTML
"<TR><TH>$proto</TH>\n";
foreach $f (@timerFieldsAll) {
($f =~ m/^Time/o) && next;
printf RESULTSHTML "<TH>%s/sec</TH> ",
($fieldNames{$f}) ? $fieldNames{$f} : $f;
}
print RESULTSHTML
"</TR>\n";
foreach $n (@{$protocolFields{$proto}}) {
my $t = $n; # dont modify original list
unless ($t =~ /^\[(\w+)\]$/) { # scalar case
next; # skip scalars for now
# do scalar counters. Column should line up with "Try"
printf RESULTSHTML "<TR ALIGN=RIGHT><TH>%s</TH>\n",
($timerNames{$t}) ? $timerNames{$t} : $t;
printf RESULTSHTML
"<TD>%.3f</TD> ",
$finals{$proto}->{$t} / $realTestSecs;
next;
} else {
$t = $1;
}
printf RESULTSHTML "<TR ALIGN=RIGHT><TH>%s</TH>\n",
($timerNames{$t}) ? $timerNames{$t} : $t;
foreach $f (@timerFieldsAll) {
($f =~ m/^Time/o) && next;
if ($f =~ m/Bytes/o) {
printf RESULTSHTML
"<TD>%s</TD> ",
kformat ($finals{$proto}->{$t}->{$f} / $realTestSecs);
} else {
printf RESULTSHTML
"<TD>%.3f</TD> ",
$finals{$proto}->{$t}->{$f} / $realTestSecs;
}
}
print RESULTSHTML "</TR>\n";
}
printf RESULTSHTML "</TABLE> <BR>\n\n";
}
print RESULTSHTML <<END;
<BR>
<CENTER>
<A NAME=GraphSection></A>
END
}
%genplotGraphs = ();
# Call genplot; and, if a graph is generated, insert the HTML reference to it
sub genHTMLReportGraph {
my $name = shift;
my $title = shift;
my $label = shift;
my $protos = shift || die "genHTMLReportGraph: '$name' missing protocols";
my $field = shift;
my $vars = shift || die "genHTMLReportGraph: '$name' missing vars";
if ($genplotGraphs{$name}) {
print "Graph $name has already been generated.\n";
return;
}
$genplotGraphs{$name} = $title;
# Delineate and tag each graph
print RESULTSHTML "<A NAME=$name><HR SIZE=4 WIDTH=\"90%\"></A>\n";
if (genPlot ($name, $title, $label, $protos, $field, $vars) > 0) {
print RESULTSHTML <<END;
<P><H3>$title</H3>
<IMG SRC=$name.$params{IMAGETYPE} ALT="$label"></P>
END
} else {
print RESULTSHTML "<BR>Graph \"$name\" contained no data (@{$vars}).<BR>\n";
}
}
# Write the final parts of the HTML page
sub genHTMLReportEnd {
print RESULTSHTML <<END;
<!-- INSERT IMAGES HERE - DO NOT DELETE THIS LINE -->
</CENTER>
<A NAME=EndSection></A>
END
if ($params{SYSCONFIG}) {
print RESULTSHTML "<HR WIDTH=\"100%\">";
print RESULTSHTML "<CENTER><H2>Details</H2></CENTER>\n";
if (($params{SYSCONFIG} =~ m/^\S+$/o)
&& (open(SCFILE, "<$params{SYSCONFIG}"))) { # see if its a file
while (<SCFILE>) {
print RESULTSHTML $_;
}
close(SCFILE);
} else { # output text directly
my $l = $params{SYSCONFIG};
$l =~ s/\\\n/\n/g; # turn quoted newline to plain newline
print RESULTSHTML $l;
}
}
print RESULTSHTML <<END;
<HR NOSHADE WIDTH="100%">
</BODY>
</HTML>
END
close(RESULTSHTML);
}
# Actually generate the standard stuff
setupTotals();
genTextReport();
genHTMLReportStart();
my $graphCount = 0;
foreach $section (@workload) {
next unless ($section->{sectionTitle} =~ /GRAPH/o);
my $name = $section->{sectionParams};
$name =~ s/name=\s*//; # strip off initial bit
my @varlist = split (/[\s,]+/, $section->{VARIABLES});
$graphCount++;
genHTMLReportGraph ($name, $section->{TITLE}, $section->{LABEL},
($section->{FIELD} =~ /Time/o)
? \@protocols : \@protocolsAll,
$section->{FIELD}, \@varlist);
}
if ($graphCount <= 0) { # use built ins
# generate the graphs we want
# NOTE: the first argument (name), must be unique; sets file name
genHTMLReportGraph ("connects",
"Number of connections attempted", "Connections/sec",
\@protocolsAll, "Try", ["conn" ]);
genHTMLReportGraph ("connections",
"Total connections", "Connections",
\@protocolsAll, "", ["connections" ]);
genHTMLReportGraph ("errors",
"Number of connection errors", "Errors/sec",
\@protocolsAll, "Error", ["conn", "banner", "login", "logout" ]);
genHTMLReportGraph ("retrieves",
"Number of messages read", "Messages/sec",
\@protocolsAll, "Try", ["retrieve" ]);
genHTMLReportGraph ("submits",
"Number of messages written", "Messages/sec",
\@protocolsAll, "Try", ["submit" ]);
genHTMLReportGraph ("commands",
"Protocol commands", "Commands/sec",
\@protocolsAll, "Try", ["cmd" ]);
genHTMLReportGraph ("readBytes",
"Bytes read", "Bytes/sec",
\@protocolsAll, "BytesR", ["login", "banner", "cmd", "retrieve", "submit", "logout" ]);
genHTMLReportGraph ("writeBytes",
"Bytes written", "Bytes/sec",
\@protocolsAll, "BytesW", ["login", "banner", "cmd", "retrieve", "submit", "logout" ]);
genHTMLReportGraph ("msgTime",
"Message transfer time", "Seconds per message",
\@protocols, "Time", ["cmd", "submit", "retrieve" ]);
genHTMLReportGraph ("setupTime",
"Connection setup time", "Seconds per connection",
\@protocols, "Time", ["conn", "banner", "login" ]);
genHTMLReportGraph ("blocks",
"Number of mailstone blocks executed", "Blocks/sec",
\@protocolsAll, "", ["blocks" ]);
}
if ($params{ADDGRAPHS}) { # pick up additional graphs
my @graphs = ();
readWorkloadFile ($params{ADDGRAPHS}, \@graphs);
foreach $section (@graphs) {
next unless ($section->{sectionTitle} =~ /GRAPH/o);
my $name = $section->{sectionParams};
$name =~ s/name=\s*//; # strip off initial bit
my @varlist = split (/[\s,]+/, $section->{VARIABLES});
$graphCount++;
genHTMLReportGraph ($name, $section->{TITLE}, $section->{LABEL},
($section->{FIELD} =~ /Time/o)
? \@protocols : \@protocolsAll,
$section->{FIELD}, \@varlist);
}
}
genHTMLReportEnd();
return 1;

View File

@@ -1,205 +0,0 @@
#!/bin/ksh
# global configuration parameters.
# Fill in defaults for anything that is not already set
# Look for testname$test_form, first
export test_form=${test_form:-""}
# string appended to every description
export desc_conf=${desc_conf:-""}
# extra arguments common to all tests
export extra_args=${extra_args:-""}
# error limit to abort sequence
export error_limit=${error_limit:-100}
# set this to only show what it will do
export only_show_it=${only_show_it:-0}
# time to allow the server to calm down after each run
export sleep_time=${sleep_time:-5}
# This is where we store the important runs
export save_dir=${save_dir:-"results.save"}
# Basic sanity test
if [[ ! -x /usr/bin/perl || ! -f .license ]] ; then # see if setup was ever run
echo "Critical files are missing. Run setup."
exit 2;
fi
find_timestamp () { # find the timestamp string from latest run
#OLD timestamp=`ls -d results/[0-9]*.[0-9][0-9][0-9][0-9]?(a-z) | tail -1`
# list all directories with the timestamp pattern
timestamp=`echo results/[0-9]*.[0-9][0-9][0-9][0-9]?([a-z])`
# strip all but the last one
timestamp=${timestamp##* }
# strip the top directory name out
timestamp=${timestamp#results/}
# return it
echo $timestamp
return 0
}
# copy last mailstone run from the current directory to good results directory
save_run () {
[[ -d $save_dir ]] || \
mkdir $save_dir
[[ $only_show_it -gt 0 ]] && return 0 # dont do anything important
if [[ -n "$last_timestamp" && -d "results/$last_timestamp/" ]] ; then
cp -pR results/$last_timestamp $save_dir/
# index probably has lots of extra junk, but its better than nothing
cp -pf results/index.html $save_dir/
fi
}
# Display and run a command. Skip if in only_show mode.
run () {
if [[ $only_show_it -gt 0 ]] ; then
echo "Would run:" "$@"
return 0
fi
echo "Running: " "$@"
"$@"
}
# Sleep. Skip if in only_show mode.
run_sleep () {
if [[ $only_show_it -gt 0 ]] ; then
echo "Would sleep:" "$@"
return 0
fi
echo "Sleeping: " "$@"
sleep "$@"
}
# for readability, just use sleep
alias sleep=run_sleep
# This runs the actual mstone run and check for errors
# compress tmp files
# Usage: run_test testname description [args...]
run_test () {
testname="$1"; shift;
desc="$1"; shift;
# see if a special version of this test exists
if [[ -f conf/$testname$test_form.wld ]] ; then
testname=$testname$test_form
fi
#oldtimestamp=`find_timestamp`
if [[ $only_show_it -gt 0 ]] ; then
echo "Would run:" mstone $testname -b "$desc $desc_conf" $extra_args "$@"
if [[ ! -f conf/$testname.wld ]] ; then
echo "Configuration Error: No such test $testname"
fi
return 0
fi
echo "\n##########################################################"
if [[ ! -f conf/$testname.wld ]] ; then
echo "CONFIGURATION ERROR: No such test $testname"
exit 2
fi
echo "\nRunning:" mstone $testname -b "$desc $desc_conf" $extra_args "$@"
# We actually bypass the mstone script
/usr/bin/perl -Ibin -- bin/mailmaster.pl -w conf/$testname.wld -b "$desc $desc_conf" $extra_args "$@"
stat=$?
# BUG if another test is running at the same time, this is wrong
timestamp="`find_timestamp`"
# test failed to even run
if [[ $stat -ne 0 ]]
then
echo "ABORT! Test failed to start"
[[ -n "$mail_list" ]] && \
mail_series "DotCom Failed run: `date`" "$mail_list"
exit 2
fi
# compress tmp files. get the csv files, too.
gzip tmp/$timestamp/* results/$timestamp/*.csv
# stick the timestamp someplace global for a save_run
export last_timestamp=$timestamp
export all_timestamps="$all_timestamps $timestamp"
# save the results
save_run
# see how many errors we hit
totline=`grep 'Total:total ' results/$timestamp/results.txt`
# strip label and first field
errors=${totline##+([+-z])+( )+([+-9])+( )}
# strip trailing fields
errors=${errors%% *}
echo "" # space things out
if [[ $errors -gt $error_limit ]] ; then
echo "ABORT! Errors ($errors) exceed error limit ($error_limit)"
[[ -n "$mail_list" ]] && \
mail_series "DotCom Aborted run: `date`" "$mail_list"
exit 1
fi
echo "Run completed OK ($errors errors). Timestamp $timestamp"
sleep $sleep_time
return 0
}
# Usage: mail_series subject "address,address,..."
mail_series () {
subject=$1; shift
file=/tmp/series$$.tar
if [[ $only_show_it -gt 0 ]] ; then
echo "Would mail results about $subject" to "$@"
return 0
fi
echo "Mailing results about $subject" to "$@"
tar cf $file $save_dir/index.html
for f in $all_timestamps ; do
tar rf $file $save_dir/$f
done
gzip $file
echo "$all_timestamps" | uuenview -b -30000 -s "$subject" -m "$@" $file.gz
rm -f $file.gz
}
# parse command line arguments
while [[ -n "$1" ]]
do
case $1 in
# -n mode, do not execute, just show
-n) only_show_it=1; shift;;
# set test form
-f) shift; test_form=$1; shift;;
# set test extra description
-d) shift; desc_conf=$1; shift;;
# Rest are to be passed in exactly
--) shift; break;;
#default, pick up as an extra arg
*) extra_args="$extra_args $1"; shift;;
esac
done

View File

@@ -1,417 +0,0 @@
#!/usr/bin/perl
# The contents of this file are subject to the Netscape Public
# License Version 1.1 (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 the Netscape Mailstone utility,
# released March 17, 2000.
#
# The Initial Developer of the Original Code is Netscape
# Communications Corporation. Portions created by Netscape are
# Copyright (C) 1999-2000 Netscape Communications Corporation. All
# Rights Reserved.
#
# Contributor(s): Dan Christian <robodan@netscape.com>
# Marcel DePaolis <marcel@netcape.com>
# Jim Salter <jsalter@netscape.com>
#
# Alternatively, the contents of this file may be used under the
# terms of the GNU Public License (the "GPL"), in which case the
# provisions of the GPL are applicable instead of those above.
# If you wish to allow use of your version of this file only
# under the terms of the GPL and not to allow others to use your
# version of this file under the NPL, indicate your decision by
# deleting the provisions above and replace them with the notice
# and other provisions required by the GPL. If you do not delete
# the provisions above, a recipient may use your version of this
# file under either the NPL or the GPL.
#####################################################
# usage: setup.pl setup|cleanup|checktime|timesync -m machine_file
# message files are expected to be in ./data/ and end with ".msg"
print "Netscape Mailstone.\nCopyright (c) 1997-2000 Netscape Communications Corp.\n";
$mode = shift; # mode must be first
# this parses the command line for -m machinefile
# also sets many defaults
do 'args.pl'|| die $@;
parseArgs(); # parse command line
setConfigDefaults(); # setup RSH and RCP
$cpcmd = "cp"; # copy files... dir
$rmcmd = "rm -f"; # remove files...
die "Must specify workload file" unless (@workload);
# Add or change client machines
sub configClients {
print "\n You can enter multiple machines like this: host1,host2\n";
my @d = <bin/*/bin>;
if (@d) {
my @d2;
foreach (@d2 = @d) { s/^bin\/// }
foreach (@d = @d2) { s/\/bin$// }
print " These OS versions are available:\n@d\n";
}
foreach $section (@workload) {
next unless ($section->{sectionTitle} =~ /CLIENT/o);
my $slist = $section->{sectionParams};
$slist =~ s/HOSTS=\s*//; # strip off initial bit
my $arch = "default OS";
$arch = $section->{ARCH} if ($section->{ARCH});
print "\nWhat is the name of the client(s) for $arch [$slist]: ";
my $ans = <STDIN>; chomp $ans;
if ($ans) {
$ans =~ s/\s//g; # strip any whitespace
fileReplaceText ($params{WORKLOAD}, "<CLIENT", $slist, $ans);
}
}
while (1) {
print "\nWhat additional client(s) [none]: ";
my $ans = <STDIN>; chomp $ans;
last unless ($ans); # done
last if ($ans =~ /^none$/i);
$ans =~ s/\s//g; # strip any whitespace
my $block = "\n<CLIENT HOSTS=$ans>\n";
print "What OS type [default]: ";
my $ans = <STDIN>; chomp $ans;
$block .= " Arch\t$ans\n" if ($ans && !($ans =~ /^default$/i));
$block .= "</CLIENT>\n";
fileInsertAfter ($params{WORKLOAD}, "^</CLIENT>", $block);
}
}
# Create a user ldif file
sub configUserLdif {
my $name = "conf/$defaultSection->{SERVER}.ldif";
print "\nWhat file to you want to create [$name]? ";
$ans = <STDIN>; chomp $ans;
$name = $ans if ($ans);
my $mode = "users";
print "\nDo you want to create a broadcast account [y]? ";
$ans = <STDIN>;
$mode .= " broadcast" unless ($ans =~ /^n/i);
my $basedn = $defaultSection->{SERVER}; # pick a default
$basedn =~ s/^.*?\.//; # strip off before first dot
$basedn = "o=$basedn";
print "\nWhat is LDAP base DN [$basedn]? ";
$ans = <STDIN>; chomp $ans;
$basedn = $ans if ($ans);
my $args = $params{MAKEUSERSARGS};
print "\n Common additional makeusers arguments:\n";
print "\t-s storeName -x storeCount \tMultiple store partitions\n";
print "\t[-3|-4] \tConfigure for NSMS 3.x or 4.x\n";
print "Any extra arguments to makeusers [$args]? ";
$ans = <STDIN>; chomp $ans;
$args = $ans if ($ans);
my $perlbin = "/usr/bin/perl";
$params{DEBUG} &&
print "$perlbin -Ibin -- bin/makeusers.pl $mode -w $params{WORKLOAD} -b '$basedn' -o $name $args\n";
print "\nGenerating $name (this can take a while)\n";
system "$perlbin -Ibin -- bin/makeusers.pl $mode -w $params{WORKLOAD} -b '$basedn' -o $name $args"
|| warn "$@";
print "LDIF generation complete. See $name\n";
print "\tSee the manual or INSTALL to create users using the LDIF file.\n";
}
# This uses a match pattern plus text to text replacements.
# Could make all changes and then write out new workload
# You would have to be carefull about sections with multi-line support.
sub configWorkload {
my $ans;
print "\nWhat is the name of the mail host [$defaultSection->{SERVER}]: ";
$ans = <STDIN>; chomp $ans;
if ($ans) {
fileReplaceText ($params{WORKLOAD},
"(SERVER|SMTPMAILFROM|ADDRESSFORMAT)",
$defaultSection->{SERVER}, $ans);
$defaultSection->{SERVER} = $ans; # needed for ldif generation
}
print "\nWhat is the user name pattern [$defaultSection->{LOGINFORMAT}]: ";
$ans = <STDIN>; chomp $ans;
if ($ans) {
fileReplaceText ($params{WORKLOAD},
"(LOGINFORMAT|ADDRESSFORMAT)",
$defaultSection->{LOGINFORMAT}, $ans);
$ans =~ s/%ld/0/; # create smtpMailFrom user
my $olduser = $defaultSection->{SMTPMAILFROM};
$olduser =~ s/@.*$//; # strip off after @
fileReplaceText ($params{WORKLOAD},
"SMTPMAILFROM",
$olduser, $ans);
}
print "\nWhat is the password pattern [$defaultSection->{PASSWDFORMAT}]: ";
$ans = <STDIN>; chomp $ans;
fileReplaceText ($params{WORKLOAD}, "PASSWDFORMAT",
$defaultSection->{PASSWDFORMAT}, $ans);
$defaultSection->{NUMLOGINS} = 100 unless ($defaultSection->{NUMLOGINS});
print "\nHow many users [$defaultSection->{NUMLOGINS}]: ";
$ans = <STDIN>; chomp $ans;
fileReplaceText ($params{WORKLOAD}, "(NUMADDRESSES|NUMLOGINS)",
$defaultSection->{NUMLOGINS}, $ans);
$defaultSection->{FIRSTLOGIN} = 0 unless ($defaultSection->{FIRSTLOGIN});
print "\nWhat is the first user number [$defaultSection->{FIRSTLOGIN}]: ";
$ans = <STDIN>; chomp $ans;
fileReplaceText ($params{WORKLOAD}, "(FIRSTADDRESS|FIRSTLOGIN)",
$defaultSection->{FIRSTLOGIN}, $ans);
unless ($params{NT}) {
configClients ();
}
print "\nDo you want to view the edited $params{WORKLOAD} [y]? ";
$ans = <STDIN>;
unless ($ans =~ /^n/i) {
print "Here is the edited $params{WORKLOAD}:\n\n";
fileShow ($params{WORKLOAD});
print "\n";
}
print "\nDo you want to generate a user LDIF file [y]? ";
$ans = <STDIN>;
unless ($ans =~ /^n/i) {
configUserLdif ();
}
}
# See if license file has been displayed
if (($mode ne "cleanup") && (! -f ".license" )) {
fileShow ("LICENSE");
print "\nDo you agree to the terms of the license? (yes/no) ";
my $ans = <STDIN>;
print "\n";
unless ($ans =~ /^yes$/i) {
print "License not agreed to.\n";
exit 0;
}
my ($sec, $min, $hour, $mday, $mon, $year) = localtime;
open (LIC, ">.license");
printf LIC "%04d$mon$mday$hour$min\n", $year+1900;
close (LIC);
}
if ($mode eq "config") { # re-run config
configWorkload ();
print "\nMake any additional changes to $params{WORKLOAD} and then re-run 'setup'\n";
exit 0;
} elsif ($mode ne "cleanup") { # check if configured
my $unconf = 0; # see if default values are in use
foreach $section (@workload) {
($section->{SERVER})
&& ($section->{SERVER} =~ /example\.com$/)
&& $unconf++;
($section->{SMTPMAILFROM})
&& ($section->{SMTPMAILFROM} =~ /example\.com$/)
&& $unconf++;
($section->{ADDRESSFORMAT})
&& ($section->{ADDRESSFORMAT} =~ /example\.com$/)
&& $unconf++;
last if ($unconf > 0);
}
if ($unconf > 0) {
print "Server has not been configured (example.com is an invalid address).\n";
print "Do you want to setup a simple configuration now [y]?";
my $ans = <STDIN>;
if ($ans =~ /^n/i) {
print "Re-run setup when you have edited the configuration.\n";
exit 0;
}
configWorkload ();
print "\nMake any additional changes to $params{WORKLOAD} and then re-run 'setup'\n";
exit 0;
}
}
if ($mode eq "timesync") {
if ($params{NT}) {
print "Timesync has no effect on NT\n";
exit 0;
}
my ($sec, $min, $hour, $mday, $mon, $year) = localtime;
$mon += 1; # adjust from 0 based to std
$systime = sprintf ("%02d%02d%02d%02d%04d.%02d",
$mon, $mday, $hour, $min, 1900+$year, $sec);
} elsif ($mode eq "checktime") {
if ($params{NT}) { # if running on NT, then only single client
print "Checktime not needed on NT\n";
exit 0;
}
mkdir ("$resultbase", 0775);
mkdir ("$tmpbase", 0775);
foreach $section (@workload) {
next unless ($section->{sectionTitle} =~ /CLIENT/o);
my $slist = $section->{sectionParams};
$slist =~ s/HOSTS=\s*//; # strip off initial bit
foreach $cli (split /[\s,]/, $slist) {
open MAKEIT, ">$tmpbase/$cli.tim";
close MAKEIT;
}
}
} elsif (($mode eq "setup") || ($mode eq "cleanup")) {
@msgs = <data/*.msg>;
foreach (@files = @msgs) { s/data\/// }
print "Found these message files:\n@files\n\n";
if ($params{NT}) { # handle NT localhost here
exit 0 if ($mode =~ /cleanup$/);
my $clipath = "bin/WINNT4.0/bin/mailclient.exe";
print "Copying $clipath and message files to $cli\n";
system "copy $clipath $params{TEMPDIR}";
foreach $f (@files) {
system "copy $f $params{TEMPDIR}";
}
exit 0; # without perl:fork, no more to do
}
}
# iterate over every client in the testbed, complete the cmd and rsh
foreach $section (@workload) {
next unless ($section->{sectionTitle} =~ /CLIENT/o);
my $slist = $section->{sectionParams};
$slist =~ s/HOSTS=\s*//; # strip off initial bit
foreach $cli (split /[\s,]/, $slist) {
my $rsh = ($section->{RSH}) ? $section->{RSH} : $params{RSH};
my $rcp = ($section->{RCP}) ? $section->{RCP} : $params{RCP};
my $tempdir;
if ($section->{TEMPDIR}) {
$tempdir = $section->{TEMPDIR};
} elsif ($params{TEMPDIR}) {
$tempdir = $params{TEMPDIR};
}
# most time critical first
if ($mode eq "timesync") {
next if ($cli =~ /^localhost$/i); # dont reset our own time
# run all these in parallel to minimize skew
next if ($section->{ARCH} eq "NT4.0");
forkproc ($rsh, $cli, "date $systime");
}
elsif ($mode eq "checktime") {
# run all these in parallel to minimize skew
forkproc ($rsh, $cli, ($section->{ARCH} eq "NT4.0")
? "time" : "date",
"/dev/null", "$tmpbase/$cli.tim");
}
elsif ($mode eq "setup") {
my ($clibin) = split /\s/, (($section->{COMMAND})
? $section->{COMMAND}
: $params{CLIENTCOMMAND});
my $clipath = "bin/$clibin";
if ($section->{ARCH}) {
if (-x "bin/$section->{ARCH}/bin/$clibin") {
$clipath="bin/$section->{ARCH}/bin/$clibin";
} else {
print "Requested OS $section->{ARCH} $cli not found. Using default.\n";
}
}
my $rdir = ($tempdir) ? "$tempdir/" : ".";
# chmod so that the remote files can be easily cleaned up
my $rcmd = "chmod g+w @files $clibin; uname -a";
$rcmd = "cd $tempdir; " . $rcmd if ($tempdir);
$rdir =~ s!/!\\!g if ($section->{ARCH} eq "NT4.0");
if ($cli =~ /^localhost$/i) {
die "TEMPDIR must be set for 'localhost'\n"
unless ($tempdir);
die "Invalid local NT copy. Should never get here.\n"
if ($section->{ARCH} eq "NT4.0"); # should never happen
print "Copying $clipath and message files to $rdir\n";
system ("$cpcmd @msgs $clipath $rdir");
system ($rcmd);
} else {
print "$rcp $clipath @msgs $cli:$rdir\n" if ($params{DEBUG});
print "Copying $clipath and message files to $cli:$rdir\n";
system (split (/\s+/, $rcp), $clipath, @msgs, "$cli:$rdir");
next if ($section->{ARCH} eq "NT4.0"); # chmod not valid
print "rcmd='$rcmd'\n" if ($params{DEBUG});
system (split (/\s+/, $rsh), $cli, $rcmd);
}
print "\n";
}
elsif ($mode eq "cleanup") {
if ($params{DEBUG}) { # get debug files
print "Cleaning up debug files on $cli\n";
my $rcmd = ($section->{ARCH} eq "NT4.0") ? "DEL" : "$rmcmd";
$rmcmd .= " mstone-debug.[0-9]*";
$rcmd = "cd $tempdir; " . $rcmd if ($tempdir);
$rcmd =~ s/;/&&/g if ($section->{ARCH} eq "NT4.0");
if ($cli =~ /^localhost$/i) {
die "TEMPDIR must be set for 'localhost'\n"
unless ($tempdir);
system ($rcmd);
} else {
system (split (/\s+/, $rsh), $cli, $rcmd);
}
} else {
print "Cleaning $cli\n";
my $rcmd = ($section->{ARCH} eq "NT4.0") ? "DEL" : "$rmcmd";
$rcmd .= " $clibin @files";
$rcmd = "cd $tempdir; " . $rcmd if ($tempdir);
$rcmd =~ s/;/&&/g if ($section->{ARCH} eq "NT4.0");
if ($cli =~ /^localhost$/i) {
die "TEMPDIR must be set for 'localhost'\n"
unless ($tempdir);
system ($rcmd);
} else {
system (split (/\s+/, $rsh), $cli, $rcmd);
}
}
}
else {
die "Couldn't recognize mode $mode!\n";
}
}
}
# wait for children to finish
if (($mode eq "timesync") || ($mode eq "checktime")) {
$pid = wait();
while ($pid != -1) {
$pid = wait();
}
}
# Print the results of the time checks
if ($mode eq "checktime") {
print "Time from each client:\n";
foreach $section (@workload) {
next unless ($section->{sectionTitle} =~ /CLIENT/o);
my $slist = $section->{sectionParams};
$slist =~ s/HOSTS=\s*//; # strip off initial bit
foreach $cli (split /[\s,]/, $slist) {
open TIMEFILE, "$tmpbase/$cli.tim"
|| warn "Counldn't open $tmpbase/$cli.tim\n";
printf "%32s: ", $cli;
while (<TIMEFILE>) { print; last;} # single line (2 on NT)
close(TIMEFILE);
unlink "$tmpbase/$cli.tim";
}
}
}

View File

@@ -1,38 +0,0 @@
# common setup info for tests
# See sample.wld for detailed usage
# Information on how the test is distributed and reported
# Test independent configuration
<CONFIG>
comments Netscape MSG4.15
sysConfig conf/sample.html # File for additonal system config
# Debug with short runs and a few clients, then increase test time
# These get overridden in the test specific files (or the command line)
clientCount 5 # nominal clientCount (usually overriden)
rampTime 10s
time 30s
# each test should set a title in their CONFIG section
# This is a reminder when using old test workloads
title Need to set test title
</CONFIG>
# Specify client machines
<CLIENT HOSTS=localhost>
</CLIENT>
# Information on the test itself
# Use the <Default> tag to set command defaults
<DEFAULT>
server mailhost.example.com
smtpMailFrom mailtestuser0@mailhost.example.com
loginFormat mailtestuser%ld
addressFormat mailtestuser%ld@mailhost.example.com
passwdFormat myPassword
numLogins 100
firstLogin 0
numAddresses 100
firstAddress 0
</DEFAULT>

View File

@@ -1,10 +0,0 @@
# MailStone workload configuration file. See sample.wld for detailed usage
# Typical HTTP GETs
<includeOnce conf/general.wld>
<HTTP>
weight 100
numLoops 1
httpcommand GET /
</HTTP>

View File

@@ -1,74 +0,0 @@
#!/bin/ksh
# fire off the series of Mailstone IMAP tests
# To test series setup, do: go_imap -n
# Look for testname$test_form, first. Override with: go_series -f <string>.
export test_form="_mail02"
export test_host="mail02"
# string appended to every description. Override with: go_series -d <string>.
export desc_conf="12 CPUs"
# Extra arguments common to all tests. Any other args go here.
# Note that arguments with embedded spaces wont work here.
# Instead use: go_series -- <args...>
export extra_args=""
# error limit to abort sequence
export error_limit=500
# time to allow the server to calm down after each run (seconds)
export sleep_time=120
# who to mail results to
#export mail_list="me@example.com,you@example.com"
export mail_list=""
# Get all the helper functions
. test_utils.ksh
### This is where the series of tests is defined
# clean and re-start server
if [[ $only_show_it -gt 0 ]] ; then
echo "Would run:" "$@"
return 0
else
# BUG: rsh never returns.
# individual commands in clean work fine, but fail as a whole
rsh -n $test_host /bin/ksh /iplanet/bin/clean$test_form &
sleep 300 && kill -9 $!
wait
fi
# check our setup
run timesync
###echo "DEBUG exit" && exit 0
run_test popdel 'Create mailboxes (random order)' -t 60m maxblocks=100000 "$@"
run_test allpop 'Create mailboxes (exhaustive)' "$@"
run_test imaplogin 'IMAP login rate' "$@"
run_test smtp10k-5-5k 'Deliver 5, 5k messages to 10k users' "$@"
sleep 200 # let queue drain (2000/(10 msg/sec))
run_test imapread10k 'IMAP Message downloads 5k from 10k users' "$@"
run_test smtp10k-5-5k 'Deliver 5, 5k messages to 10k users' "$@"
sleep 200 # let queue drain (2000/(10 msg/sec))
run_test imapread 'IMAP Message downloads 5k' "$@"
run_test imapsmtp-throttle 'Combined IMAP-SMTP load (1 of 3)' "$@"
run_test imapsmtp-throttle 'Combined IMAP-SMTP load (2 of 3)' "$@"
run_test imapsmtp-throttle 'Combined IMAP-SMTP load (3 of 3)' "$@"
# Some messages will be left from previous test
run_test imapmaxusers 'IMAP 30K simultaneous users' "$@"
# e-mail the whole batch
[[ -n "$mail_list" ]] && \
mail_series "DotCom IMAP: `date`" "$mail_list"

View File

@@ -1,19 +0,0 @@
# MailStone workload configuration file. See sample.wld for detailed usage
# Typical IMAP checks/reads
<includeOnce conf/general.wld>
<CONFIG> # test specific config
title IMAP reads
clientCount 100 # since IMAP has long sleeps, use lots of clients
</CONFIG>
<IMAP4>
weight 100
#leaveMailOnServer 1
idleTime 2s # time between login and first download check
loopDelay 5m # time between download checks
numLoops 10 # how many check to do before closing the connection
blockTime 2s # time between logout and next login (or other block)
</IMAP4>

View File

@@ -1,84 +0,0 @@
#!/bin/ksh
# fire off the series of Mailstone tests
# To test series, do: go_series -n
# Look for testname$test_form, first. Override with: go_series -f <string>.
export test_form="_mail02"
export test_host="mail02"
# string appended to every description. Override with: go_series -d <string>.
export desc_conf="12 CPUs"
# Extra arguments common to all tests. Any other args go here.
# Note that arguments with embedded spaces wont work here.
# Instead use: go_series -- <args...>
export extra_args=""
# error limit to abort sequence
export error_limit=500
# time to allow the server to calm down after each run (seconds)
export sleep_time=120
# who to mail results to
#export mail_list="me@example.com,you@example.com"
export mail_list=""
# Get all the helper functions
. test_utils.ksh
### This is where the series of tests is defined
# clean and re-start server
if [[ $only_show_it -gt 0 ]] ; then
echo "Would run:" "$@"
return 0
else
# BUG: this never returns. rsh never returns
# individual commands in clean work fine, but fail as a whole
rsh -n $test_host /bin/ksh /iplanet/bin/clean$test_form &
sleep 300 && kill -9 $!
wait
fi
# check our setup
run timesync
###echo "DEBUG exit" && exit 0
run_test popdel 'Create mailboxes (random order)' -t 60m maxblocks=100000 "$@"
run_test allpop 'Create mailboxes (exhaustive)' "$@"
run_test popdel 'Empty checks: never used (1 of 3)' "$@"
run_test popdel 'Empty checks: never used (2 of 3)' "$@"
run_test popdel 'Empty checks: never used (3 of 3)' "$@"
run_test smtp10k-5-5k 'Deliver 5, 5k messages to 10k users' "$@"
sleep 200 # let queue drain (2000/(10 msg/sec))
run_test popsave10k 'Message downloads 5k from 10k users (1 of 3)' "$@"
run_test popsave10k 'Message downloads 5k from 10k users (2 of 3)' "$@"
run_test popsave10k 'Message downloads 5k from 10k users (3 of 3)' "$@"
run_test popsave 'Message downloads 5k (1 of 3)' "$@"
run_test popsave 'Message downloads 5k (2 of 3)' "$@"
run_test popsave 'Message downloads 5k (3 of 3)' "$@"
run_test popsmtp-throttle 'Combined load (1 of 3)' "$@"
run_test popsmtp-throttle 'Combined load (2 of 3)' "$@"
run_test popsmtp-throttle 'Combined load (3 of 3)' "$@"
run_test smtp100k 'SMTP delivery rate' "$@"
run_test popclean 'Message downloads/delete 5k ' "$@"
run_test popdel 'Empty checks (1 of 3)' "$@"
run_test popdel 'Empty checks (2 of 3)' "$@"
run_test popdel 'Empty checks (3 of 3)' "$@"
# e-mail the whole batch
[[ -n "$mail_list" ]] && \
mail_series "DotCom POP: `date`" "$mail_list"

View File

@@ -1,15 +0,0 @@
# MailStone workload configuration file. See sample.wld for detailed usage
# Typical POP checks/reads
<includeOnce conf/general.wld>
<CONFIG> # test specific config
title POP reads
clientCount 50
</CONFIG>
<POP3>
weight 100
numLoops 9999 # will close when messages run out
#leaveMailOnServer 1
</POP3>

Some files were not shown because too many files have changed in this diff Show More