⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 pgpaddhdr.c

📁 PGP8.0源码 请认真阅读您的文件包然后写出其具体功能
💻 C
📖 第 1 页 / 共 2 页
字号:
/*____________________________________________________________________________
	Copyright (C) 2002 PGP Corporation
	All rights reserved.

	$Id: pgpAddHdr.c,v 1.10 2002/08/06 20:11:03 dallen Exp $
____________________________________________________________________________*/

/*
 * pgpAddHdr.c -- Add a PGP Packet Header to a data stream.
 *
 * Written by:	Derek Atkins <warlord@MIT.EDU>
 */
#include "pgpConfig.h"

#include <stdio.h>
#include <string.h>

#include "pgpDebug.h"
#include "pgpAddHdr.h"
#include "pgpPktByte.h"
#include "pgpAnnotate.h"
#include "pgpFIFO.h"
#include "pgpMem.h"
#include "pgpPipeline.h"
#include "pgpErrors.h"
#include "pgpContext.h"

#define ADDHEADERMAGIC	0xadd0b11e

/* Define BIGBLOCKS to get larger buffers */
#ifndef BIGBLOCKS
#define BLOCK_SIZE 12
#define BUFFER_SIZE (1 << BLOCK_SIZE)	/* 2^10 == 4k */
#else /* BIGBLOCKS */
#define BLOCK_SIZE 18
#define BUFFER_SIZE (1 << BLOCK_SIZE)	/* 2^18 == 256K */
#endif /* BIGBLOCKS */


/* This module works in two different ways.  For V3 and earlier, it
 * uses "old-format" (PGP 2 compatible) packet lengths, which go at
 * the front of the packet.  For V4 and later, it uses new-format
 * packets.  The V3 mode uses the fifo field, and the V4 mode uses the
 * buffer, bufptr and bufwrite fields.
 *
 * The V3 mode uses the Write and SizeAdvise functions, and V4 uses
 * BufferWrite and BufferSizeAdvise.
 *
 * In V3 mode, dowrite is false while we are buffering up the packet.
 * It is set true once we get the final length, at which point we
 * can output the header and flush out the data.
 *
 * In V4 mode, dowrite is false until we have filled up the buffer,
 * then we set it to true and output the partial body length byte
 * and the buffer full of data, then set it to false again.
 */
typedef struct AddHdrContext {
	PGPPipeline		pipe;
	
	PGPFifoDesc const *fifod;
	PGPFifoContext *fifo;
	PGPPipeline *tail;
	PGPByte header[5];			/* pktbyte + 4byte length */
	PGPByte *ptr;
	int hdrlen;			/* actual header length */
	int dowrite;
	int sizeknown;			/* bytes is valid */
	PGPFileOffset bytes;		/* sizeAdvise() promise */
	PgpVersion version;
	PGPByte *buffer;		/* Buffer, used in V4 mode */
	PGPByte *bufwrite;		/* "Fill" pointer for buffer */
	PGPByte *bufptr;		/* "Empty" pointer for buffer */
	int buflen;				/* Number of bytes in buffer */
	int midflush;			/* V4 mode: buffer bytes to be literally sent */
#ifdef BIGBLOCKS
	int lastblock;			/* V4 mode: true if on last block of data */
#endif /* BIGBLOCKS */
	int scope_depth;
	DEBUG_STRUCT_CONSTRUCTOR( AddHdrContext )
} AddHdrContext;

/*
 * Return the largest x such that 2^x <= n, n>0
 * Return -1 if n==0
 */
static int
NumToBits(unsigned int n)
{
	int i;

	if (!n)
		return -1;

	for (i=0; n > 1; i++)
		n >>= 1;

	return i;
}

/* Used in V3 or V4 mode.  Flush out header.  Only does anything once. */
static PGPError
FlushHeader(AddHdrContext *context)
{
	PGPError	error;
	size_t retlen;

	while (context->hdrlen) {
		retlen = context->tail->write(context->tail,
					       context->ptr,
					       context->hdrlen,
					       &error);
		context->ptr += retlen;
		context->hdrlen -= retlen;
		if (error)
			return error;
	}
	return( kPGPError_NoErr );
}

/* Used in V4 mode.  Flush out all bytes from the buffer. */
static PGPError
FlushBuffer(AddHdrContext *context)
{
	PGPError	error;
	size_t retlen;

	while (context->buflen) {
		retlen = context->tail->write(context->tail,
					       context->bufptr,
					       context->buflen,
					       &error);
		context->bufptr += retlen;
		context->buflen -= retlen;
		if (error)
			return error;
	}
	return( kPGPError_NoErr );
}

/* Used only in V4 mode.  Flush out all bytes from the buffer; first
 * midflush of them, then the remainder with power-of-two sized
 * partial body length packets until they're all flushed.
 */
static PGPError
ForceFlush(AddHdrContext *context)
{
	PGPError	error;
	int bufl, flushed;

	while (context->buflen) {
		/* First, flush out any mid-flush we might have */

		bufl = context->buflen;
		flushed = context->midflush;
		context->buflen = context->midflush;

		error = FlushBuffer(context);

		flushed -= context->buflen;
		context->midflush = context->buflen;
		context->buflen = bufl - flushed;

		if (error || (context->buflen == 0))
			return error;

#ifndef BIGBLOCKS
		/*
		 * Now, figure out how much should be sent in the
		 * next sub-packet
		 */
		bufl = NumToBits(context->buflen);
		if (bufl < 0)
			break;

		context->bufptr--;
		context->buflen++;
		*(context->bufptr) = 0xE0 + bufl;
		context->midflush = (1<<bufl) + 1;
#else /* BIGBLOCKS */
		if (context->lastblock && PKTLEN_ONE_BYTE(context->buflen)) {
			context->bufptr--;
			context->buflen++;
			context->bufptr[0] = PKTLEN_1BYTE(context->buflen);
			context->midflush = context->buflen;
		} else if (context->lastblock && PKTLEN_TWO_BYTES(context->buflen)) {
			context->bufptr -= 2;
			context->buflen += 2;
			context->bufptr[0] = PKTLEN_BYTE0(context->buflen);
			context->bufptr[1] = PKTLEN_BYTE1(context->buflen);
			context->midflush = context->buflen;
		} else {
			bufl = NumToBits(context->buflen);
			if (bufl < 0)
				break;
			if( context->lastblock && ((1<<bufl)==context->buflen) ) {
				/* Last block must not be partial body length */
				bufl--;
			}
			context->bufptr--;
			context->buflen++;
			*(context->bufptr) = 0xE0 + bufl;
			context->midflush = (1<<bufl) + 1;
		}
#endif /* BIGBLOCKS */
	}

	return( kPGPError_NoErr );
}

/* This is used only in V3 (old-style packets) mode.  Flush out header,
 * and everything from the fifo.
 */
static PGPError
DoFlush(AddHdrContext *context)
{
	PGPError	error = kPGPError_NoErr;
	size_t retlen;
	PGPByte const *p;
	PGPSize len;

	error = FlushHeader(context);
	if (error)
		return error;

	/* Next, try to flush anything that we have buffered in the fifo */
	p = pgpFifoPeek (context->fifod, context->fifo, &len);
	while (len) {
		retlen = context->tail->write(context->tail,
					       p, len, &error);
		pgpFifoSeek (context->fifod, context->fifo, retlen);
		if (error)
			return error;
		
		p = pgpFifoPeek (context->fifod, context->fifo, &len);
	}
	return error;
}

/* This is called in both V3 and V4 mode. */
static PGPError
Flush(PGPPipeline *myself)
{
	AddHdrContext *context;
	PGPError	error;

	pgpAssert(myself);
	pgpAssert(myself->magic == ADDHEADERMAGIC);

	context = (AddHdrContext *)myself->priv;
	pgpAssert(context);
	pgpAssert(context->tail);

	if (context->buffer) {
		/* V4 mode */
		error = FlushHeader(context);
		if (error)
			return error;

		/* Using the new packets -- force a flush of the buffer */
		if (context->dowrite) {
			error = FlushBuffer(context);
			if (error)
				return error;
		} else {
			error = ForceFlush(context);
			if (error)
				return error;
		}

	} else {
		/* V3 mode */
		/* Using the fifo */

		if (!context->dowrite)
			return kPGPError_BadParams;

		error = DoFlush(context);
		if (error)
			return error;
	}

	return context->tail->flush(context->tail);
}

/* This is only used in V4 mode */
/* Note the order here; once we fill a buffer we don't write it out
 * until the next time we are called.  This way we won't write the
 * last buffer here in case the file is a multiple of the buffer size.
 * We are required to use a non-partial-body-length buffer for the
 * last one.  Possible hole: if flush is called when we are holding
 * exactly one buffer-full, we will write it out, and if that then
 * turns out to be the last buffer in the message, we would not
 * terminate it properly.  However we do not in fact call flush at
 * present.
 */
static size_t
BufferWrite(PGPPipeline *myself, PGPByte const *buf, size_t size,
	     PGPError *error)
{
	AddHdrContext *context;
	size_t size0 = size;
	int t;

	pgpAssert(myself);
	pgpAssert(myself->magic == ADDHEADERMAGIC);
	pgpAssert(error);

	context = (AddHdrContext *)myself->priv;
	pgpAssert(context);
	pgpAssert(context->tail);
	pgpAssert(context->buffer);

	*error = FlushHeader(context);
	if (*error)
		return 0;

	do {
		/* If we are in the middle of a block, flush it out */
		if (context->dowrite) {
			*error = FlushBuffer(context);
			if (*error)
				break;

			context->dowrite = 0;
			context->bufptr = context->buffer + 2;
			context->bufwrite = context->bufptr;
		}

		/* Try to fill up the buffer */
		t = pgpMin(((size_t)(BUFFER_SIZE - context->buflen)), size);
		if (t) {
			memcpy(context->bufwrite, buf, t);
			buf += t;
			size -= t;
			context->bufwrite += t;
			context->buflen += t;
		}

		/*
		 * If we have a full block, write out the length
		 * and then write out the block
		 */
		if (context->buflen == BUFFER_SIZE) {
			context->dowrite = 1;
			context->bufptr--;
			context->buflen++;

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -