/* * Copyright (c) 2000-2001 Apple Computer, Inc. All Rights Reserved. * * The contents of this file constitute Original Code as defined in and are * subject to the Apple Public Source License Version 1.2 (the 'License'). * You may not use this file except in compliance with the License. Please obtain * a copy of the License at http://www.apple.com/publicsource and read it before * using this file. * * This Original Code and all software distributed under the License are * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESS * OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, INCLUDING WITHOUT * LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR * PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. Please see the License for the * specific language governing rights and limitations under the License. */ #if defined (USE_EXP_BUF) || defined (USE_GEN_BUF) /* * .../c-lib/src/exp-buf.c - buffer routines for the buffer structure * * * --------- ---------- * | ExpBuf |<------>| ExpBuf |<------> ...ExpBufs * | |--- | |--- * ---------- | ---------- | * V V * -------- -------- * | DATA | | DATA | * | BLK | | BLK | * -------- -------- * * * ExpBuf * -------------- * | readError | * | writeError | * | dataStart |----------- * | dataEnd |-------- | * | curr |------ | | * | next | | | | * | prev | | | | data * | blkStart |=====|=|==|==>-------------------------- * | blkEnd |--- | | | | | (each line * -------------- | | | | | | reps a byte * | | | |-->| - - - - - - - - - - - -| diff in addr) * | | | | valid | * | |-|----->| | * | | | data | * | | | | * | | | - - - - - - - - - - - -| * | |----->|(one byte after last valid data byte) * | | | * | -------------------------- * |-----------> (one byte after last byte in data blk) * * * readError - set to non-zero to indicate attempt to read past end of * of data * writeError- set to non-zero to indicate write error. * Set if Alloc of new buf fails * dataStart - pts to first VALID data byte ie *dataStart is first byte * dataEnd - pts to byte AFTER last VALID byte *dataEnd is not in the data * but *(dataEnd -1) is in the data * curr - used for current read ptr - points to next byte to be read * so *curr is the next byte to be read. * next - pts to next BUF in list, NULL for last BUF in list * prev - pts to prev BUF in list, NULL for first BUF in list * blkStart - pts to start of the data blk. *blkStart is first byte * in the buffer's data blk. * blkEnd - pts to byte AFTER last writable byte of the dataBlk. * *(blkEnd-1) is the last byte in the buffer's data blk. * * NOTES: * - dataEnd is currently always the same as blkEnd * - at End Of Data (EOD) (no more data to be read) * if (curr == dataEnd) * - buffer has no valid data if (dataStart == dataEnd) * - number of valid data bytes = (dataEnd - dataStart) * - size of the data block = (blkEnd - blkStart) * * - the write reverse routines modify dataStart * - the read routines modify the curr ptr. * - there are no 'forward' write routines at the moment * (if there were they would adjust dataEnd) * * * Copyright (C) 1992 Michael Sample and the University of British Columbia * * This library is free software; you can redistribute it and/or * modify it provided that this copyright/license information is retained * in original form. * * If you modify this file, you must clearly indicate your changes. * * This source code is distributed in the hope that it will be * useful, but WITHOUT ANY WARRANTY; without even the implied warranty * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * * $Header: /cvs/Darwin/Security/SecuritySNACCRuntime/c-lib/src/exp-buf.c,v 1.1.1.1 2001/05/18 23:14:08 mb Exp $ * $Log: exp-buf.c,v $ * Revision 1.1.1.1 2001/05/18 23:14:08 mb * Move from private repository to open source repository * * Revision 1.2 2001/05/05 00:59:25 rmurphy * Adding darwin license headers * * Revision 1.1.1.1 1999/03/16 18:06:32 aram * Originals from SMIME Free Library. * * Revision 1.2 1995/07/27 09:05:29 rj * merged type table routines and code used by its gen-bufs. * * changed `_' to `-' in file names. * * Revision 1.1 1994/08/28 09:46:05 rj * first check-in. for a list of changes to the snacc-1.1 distribution please refer to the ChangeLog. * */ #include "asn-config.h" #include "gen-buf.h" #include "exp-buf.h" /* default buffer data block size (used when allocating) */ unsigned long expBufDataBlkSizeG = 1024; #if defined (DEBUG) || defined (USE_GEN_BUF) /* otherwise macros */ #ifdef USE_GEN_BUF /* * casts are used to overcome void * - ExpBuf * conflict * be careful if you modify param lists etc. */ static struct GenBuf expBufOpsG = { (BufGetByteFcn) ExpBufGetByte, (BufGetSegFcn) ExpBufGetSeg, (BufCopyFcn) ExpBufCopy, (BufSkipFcn) ExpBufSkip, (BufPeekByteFcn) ExpBufPeekByte, (BufPeekSegFcn) ExpBufPeekSeg, (BufPeekCopyFcn) ExpBufPeekCopy, (BufPutByteRvsFcn) ExpBufPutByteRvs, (BufPutSegRvsFcn) ExpBufPutSegRvs, (BufReadErrorFcn) ExpBufReadError, (BufWriteErrorFcn) ExpBufWriteError, NULL, NULL }; #endif /* * remember: ExpBufs are used via a handle (double ptr) * in the standardized buffer routines. This allows * the 'current' expbuf in the list of expbuf to be the arg. * The list is doubly linked so you can always find * the head or tail given any expbuf in the list */ void PutExpBufInGenBuf PARAMS ((eb, gb), ExpBuf *eb _AND_ GenBuf *gb) { *gb = expBufOpsG; /* structure assignemnt */ gb->bufInfo = &gb->spare; /* handle to expbuf */ gb->spare = eb; } /* PutExpBufInGenBuf */ /* * sets the size of the data block to attach to * an ExpBuf when allocating a new one */ void ExpBufInit PARAMS ((dataBlkSize), unsigned long dataBlkSize) { expBufDataBlkSizeG = dataBlkSize; } /* InitBuffers */ /* * Allocates and returns an uninitialized ExpBuf with * no a data attached. */ ExpBuf* ExpBufAllocBuf() { return (ExpBuf*)malloc (sizeof (ExpBuf)); } void ExpBufFreeBuf PARAMS ((ptr), ExpBuf *ptr) { free (ptr); } char* ExpBufAllocData() { return (char*)malloc (expBufDataBlkSizeG); } void ExpBufFreeData PARAMS ((ptr), char *ptr) { free (ptr); } void ExpBufFreeBufAndData PARAMS ((b), ExpBuf *b) { ExpBufFreeData ((b)->blkStart); ExpBufFreeBuf (b); } /* ExpBufFreeBufAndData */ ExpBuf* ExpBufNext PARAMS ((b), ExpBuf *b) { return b->next; } ExpBuf* ExpBufPrev PARAMS ((b), ExpBuf *b) { return b->prev; } int ExpBufReadError PARAMS ((b), ExpBuf **b) { return (*b)->readError; } /* ExpBufReadError */ int ExpBufWriteError PARAMS ((b), ExpBuf **b) { return (*b)->writeError; } /* ExpBufWriteError */ /* * set curr ptr used in reads to the first byte * to be read */ void ExpBufResetInReadMode PARAMS ((b), ExpBuf *b) { b->curr = b->dataStart; b->readError = 0; b->writeError = 1; /* catch wrong mode errors */ } /* * sets dataStart to end of buffer * so following writes (backward) * over-write any existing data associated with * the buffer */ void ExpBufResetInWriteRvsMode PARAMS ((b), ExpBuf *b) { b->dataEnd = b->dataStart = b->blkEnd; b->writeError = 0; b->readError = 1; /* catch wrong mode errors */ } /* * returns true if no more data can be read from * the given buffer. only valid when buffer in read (fwd) * mode. */ int ExpBufAtEod PARAMS ((b), ExpBuf *b) { return b->curr == b->dataEnd; } /* * returns true if no more reverse writes can be done * to the buffer. Only valid when buffers in reverse * write mode */ int ExpBufFull PARAMS ((b), ExpBuf *b) { return (b)->dataStart == (b)->blkStart; } /* * returns true if the given buffer has no * valid data in it's data block */ int ExpBufHasNoData PARAMS ((b), ExpBuf *b) { return b->dataStart == b->dataEnd; } /* * returns the number of valid data bytes in the * given buffer's data block */ unsigned long ExpBufDataSize PARAMS ((b), ExpBuf *b) { return b->dataEnd - b->dataStart; } /* * returns size of data block that is attached to * the given buffer. */ unsigned long ExpBufDataBlkSize PARAMS ((b), ExpBuf *b) { return b->blkEnd - b->blkStart; } /* * returns a ptr the beginning of the valid data of * the given buffer. * returns NULL is there is no valid data. */ char* ExpBufDataPtr PARAMS ((b), ExpBuf *b) { if (ExpBufHasNoData (b)) return NULL; else return b->dataStart; } #endif /* DEBUG || USE_EXP_BUF */ /* * returns last ExpBuf in a list of bufs. * The given buf can be any buf in the list. */ ExpBuf* ExpBufListLastBuf PARAMS ((b), ExpBuf *b) { for (; b->next != NULL; b = b->next) ; return b; } /* * returns first buf in a list of bufs . * The given buf can be any buf in the list */ ExpBuf* ExpBufListFirstBuf PARAMS ((b), ExpBuf *b) { for (; b->prev != NULL; b = b->prev) ; return b; } /* * Allocates a Buf and allocates an attaches a * data block of expBufDataBlkSizeG to that buffer. * sets up the blk for writing in that the data start * and data end point to the byte after the data blk. */ ExpBuf* ExpBufAllocBufAndData() { ExpBuf *retVal; retVal = ExpBufAllocBuf(); if (retVal == NULL) return NULL; retVal->readError = 0; retVal->writeError = 0; retVal->blkStart = ExpBufAllocData(); if (retVal->blkStart == NULL) { ExpBufFreeBuf (retVal); return NULL; } retVal->next = NULL; retVal->prev = NULL; retVal->curr = retVal->blkEnd = retVal->dataStart = retVal->dataEnd = retVal->blkStart + expBufDataBlkSizeG; return retVal; } /* ExpBufAllocBufAndData */ /* * Frees ExpBuf's and associated data blocks after * after (next ptr) and including the given buffer, b. */ void ExpBufFreeBufAndDataList PARAMS ((b), ExpBuf *b) { ExpBuf *tmp; for (; b != NULL;) { tmp = b->next; ExpBufFreeBufAndData (b); b = tmp; } } /* ExpBufFreeBufAndDataList */ /* * puts the given data in a buffer and sets it up for reading * the data. This results in a "full" buffer with a data * blk size of given data's len */ void ExpBufInstallDataInBuf PARAMS ((buf, data, len), ExpBuf *buf _AND_ char *data _AND_ unsigned long int len) { buf->readError = 0; buf->writeError = 0; buf->blkStart = buf->dataStart = buf->curr = data; buf->next = NULL; buf->prev = NULL; buf->blkEnd = buf->dataEnd = data + len; } /* ExpBufInstallDataInBuf */ /* Buf reading and writing routines follow */ /* READ * returns the next byte to be read without * advancing the pointer. No check for end of * data - this is lame */ unsigned char ExpBufPeekByte PARAMS ((b), ExpBuf **b) { if ((*b)->curr == (*b)->dataEnd) (*b)->readError = 1; return *(*b)->curr; } /* ExpBufPeek */ #if TTBL /* READ * returns a ptr to the next "len" bytes (contiguous). * if "len" is greater than the available contiguous bytes * len is set the the number of contig. bytes the returned * ptr references. The next call to ExpBufGetSeg or other ExpBufGet * routines will return a ptrsto the SAME bytes (ie curr is NOT advanced). * * Does not change the buffer * * if the value returned in the len param is zero or the * returned char * is NULL then at end of data. * */ char* ExpBufPeekSeg PARAMS ((b, len), ExpBuf **b _AND_ unsigned long int *len) { int bytesLeft; if (ExpBufAtEod (*b)) { *len = 0; return NULL; } /* check for "buffer fault" and adjust "peeked" len */ if (((*b)->dataEnd - (*b)->curr) <= *len) *len = bytesLeft; return (*b)->curr; } /* ExpBufPeekSeg */ /* READ * copy the next len chars in the buffer to the given * dst char string. The curr ptr in the buffer is * NOT advanced so the next read will get the same bytes. */ int ExpBufPeekCopy PARAMS ((dst, b, len), char *dst _AND_ ExpBuf **b _AND_ unsigned long int len) { unsigned long int gotLen; int totalGotLen = 0; char *srcPtr; ExpBuf *origBuf; origBuf = *b; gotLen = len; while (1) /* optimize std path - eg only one ExpBufGetPeekSeg needed */ { srcPtr = ExpBufPeekSeg (b, &gotLen); memcpy (dst + totalGotLen, srcPtr, gotLen); totalGotLen += gotLen; if ((totalGotLen >= len) || ((*b)->next == NULL)) { *b = origBuf; return totalGotLen; } if (gotLen == 0) /* eod */ { (*b)->readError = 1; *b = origBuf; return totalGotLen; } *b = (*b)->next; /* get next buffer with valid data */ while (((*b)->next != NULL) && ExpBufHasNoData (*b)) *b = (*b)->next; /* reset current pointer to beggining of data if nec */ (*b)->curr = (*b)->dataStart; gotLen = len - totalGotLen; } /* not reached */ } /* ExpBufPeekCopy */ #endif /* TTBL */ /* READ * copy the next len chars in the buffer to the given * dst char string. The curr ptr in the buffer is advanced * appropriately */ int ExpBufCopy PARAMS ((dst, b, len), char *dst _AND_ ExpBuf **b _AND_ unsigned long int len) { unsigned long int gotLen; int totalGotLen = 0; char *srcPtr; gotLen = len; while (1) /* optimize std path - eg only one ExpBufGetSeg needed */ { srcPtr = ExpBufGetSeg (b, &gotLen); memcpy (dst + totalGotLen, srcPtr, gotLen); totalGotLen += gotLen; if (totalGotLen >= len) return totalGotLen; if (gotLen == 0) /* eod */ { (*b)->readError = 1; return totalGotLen; } gotLen = len - totalGotLen; } /* not reached */ } /* ExpBufCopy */ /* * advance the curr ptr in the given buffer over the next * len bytes */ void ExpBufSkip PARAMS ((b, len), ExpBuf **b _AND_ unsigned long int len) { unsigned long int lenRemaining; lenRemaining = len; while ((len > 0) && ExpBufGetSeg (b, &lenRemaining)) { len -= lenRemaining; if (lenRemaining == 0) { (*b)->readError = 1; return; } lenRemaining = len; } } /* ExpBufSkip */ /* READ * returns a ptr to the next "len" bytes (contiguous). * if "len" is greater than the available contiguous bytes * len is set the the number of contig. bytes the returned * ptr references. Subsequent call to ExpBufGetSeg or other ExpBufGet * routines will return ptrs to the following bytes (ie curr is advanced). * Changes *b to pt to the next buffer and sets curr for the * that buffer to dataStart if the current one has been totally read. * * if the value returned in the len param is zero or the * returned char * is NULL then at end of data (eod) * */ char* ExpBufGetSeg PARAMS ((b, len), ExpBuf **b _AND_ unsigned long int *len) { int bytesLeft; char *retVal; if (ExpBufAtEod (*b)) { *len = 0; return NULL; } bytesLeft = (*b)->dataEnd - (*b)->curr; retVal = (*b)->curr; /* check for "buffer fault" */ if (bytesLeft <= *len) { *len = bytesLeft; if ((*b)->next != NULL) { *b = (*b)->next; /* get next buffer with valid data */ while (((*b)->next != NULL) && ExpBufHasNoData (*b)) *b = (*b)->next; /* reset current pointer to beggining of data if nec */ (*b)->curr = (*b)->dataStart; } else (*b)->curr += *len; } else (*b)->curr += *len; return retVal; } /* ExpBufGetSeg */ /* * WRITE * Copies len bytes from the data pointer into the given buffer * * FILLS EXP_BUFFERS BACKWARDS! from the end of the data to the beginning * LINKS BUFFERS BACKWARDS! if a buf is full it allocs another an * puts it at the HEAD of the buffer list * * changes *b to pt to the new "prev" buffer if the current one * has been totally filled * Rvs is for REVERSE! * * modifies the dataStart pointer to reflect the new data */ void ExpBufPutSegRvs PARAMS ((b, data, len), ExpBuf **b _AND_ char *data _AND_ unsigned long int len) { int bytesLeft; ExpBuf *buf; char *dataPtr; buf = *b; if (buf->writeError) return; bytesLeft = buf->dataStart - buf->blkStart; dataPtr = data + len; /* pts to end of data to be written */ /* optimize fast path */ do { if (bytesLeft > len) /* enough room in this buffer for write */ { buf->dataStart -= len; memcpy (buf->dataStart, data, len); break; /* this is the normal exit from this loop */ } else { /* * going to fill this buffer completely, * so alloc other one (only if one is not * already linked in) */ dataPtr = dataPtr - bytesLeft; buf->dataStart = buf->blkStart; memcpy (buf->dataStart, dataPtr, bytesLeft); len -= bytesLeft; if (buf->prev == NULL) { /* alloc & insert new buf at head of buffer list */ buf = ExpBufAllocBufAndData(); if (buf == NULL) { (*b)->writeError = 1; return; } buf->next = *b; (*b)->prev = buf; } else buf = buf->prev; *b = buf; /* update head of list */ bytesLeft = buf->dataStart - buf->blkStart; } } while (1); /* not reached */ } /* ExpBufPutSegRvs */ /* * returns the next byte and advances the curr ptr by one. * sets the readError flag if there is no byte to read * (ie at end of data) */ unsigned char ExpBufGetByte PARAMS ((b), ExpBuf **b) { unsigned char retVal; if (ExpBufAtEod (*b)) { (*b)->readError = 1; return (unsigned char)0; } retVal = *(*b)->curr++; /* "buffer fault" - if end of this buf, go on to next, if any */ if (ExpBufAtEod (*b) && ((*b)->next != NULL)) { *b = (*b)->next; /* get next buffer with valid data */ while (((*b)->next != NULL) && ExpBufHasNoData (*b)) *b = (*b)->next; /* reset current pointer to beggining of data if nec */ (*b)->curr = (*b)->dataStart; } return retVal; } /* ExpBufGetByte */ /* WRITE * Puts a single octet into the buffer * writes in reverse. * allocates new buffers as nec - may change * (*b) to new buffer since writing backwards */ void ExpBufPutByteRvs PARAMS ((b, byte), ExpBuf **b _AND_ unsigned char byte) { ExpBuf *new; if ((*b)->writeError) return; *(--(*b)->dataStart) = byte; /* * check if buffer is full and alloc new one if nec * and insert it before this one since writing backwards */ if (ExpBufFull (*b)) { if ((*b)->prev == NULL) { /* * no prev buf so alloc & insert * new buf as head of buffer list */ new = ExpBufAllocBufAndData(); if (new == NULL) { (*b)->writeError = 1; return; } new->next = *b; (*b)->prev = new; *b = new; } else { (*b) = (*b)->prev; ExpBufResetInWriteRvsMode (*b); } } } /* ExpBufPutByteRvs */ void ExpBufCopyToFile PARAMS ((b, f), ExpBuf *b _AND_ FILE *f) { long int writeLen; b = ExpBufListFirstBuf (b); for ( ; b != NULL; b = ExpBufNext (b)) { writeLen = fwrite (ExpBufDataPtr (b), sizeof (char), ExpBufDataSize (b), f); if (writeLen != ExpBufDataSize (b)) fprintf (stderr, "ExpBufCopyToFile: error during writing\n"); } } #else /* !USE_EXP_BUF */ #ifdef __alpha static void dummy() { } #endif #endif /* USE_EXP_BUF */