/*----------------------------------------------------------------------- * File: CSM_VECT.C * * Copyright (c) 1995-2000 Intel Corporation. All rights reserved. *----------------------------------------------------------------------- */ #include "maf_include.h" #include "csm_vect.h" #ifdef WIN32 /* Disable the "conditional expression is constant" warning triggered by * "while (1)" loops. */ # pragma warning( disable: 4127 ) #endif /* ifdef WIN32 */ static CSSM_RETURN __CSM_CreateCompositeVectorBuffer( CSM_VECTOR *pVector ) { CSSM_RETURN rv; uint32 uTotalLength = 0; uint32 Index; uint32 Offset = 0; uint8* pBuf; /* Parameter check */ ASSERT_VALID_CSM_VECTOR( pVector ); /* How big should the buffer be? */ if ( ( rv = CSM_GetVectorLength( pVector, &uTotalLength ) ) == CSSM_OK ) { /* Allocate enough memory to hold the composite data */ pVector->TempBuffer.Data = Addin_malloc( uTotalLength, NULL ); if ( pVector->TempBuffer.Data == NULL ) { ERR( rv = CSSMERR_CSP_MEMORY_ERROR ); } else { pVector->TempBuffer.Length = uTotalLength; /* Copy each input buffer */ pBuf = pVector->TempBuffer.Data; for ( Index = 0; Index < pVector->uNumBuffers; Index++ ) { if ( pVector->Buffers[Index].Data != NULL ) { memcpy( &pBuf[Offset], pVector->Buffers[Index].Data, pVector->Buffers[Index].Length ); Offset += pVector->Buffers[Index].Length; } } } /* Allocate buffer */ } /* Get length */ return rv; } /**------------------------------------------------------------------------- ** CSM_CreateVector ** ** Description ** Initializes a CSM_VECTOR structure. A CSM_VECTOR allows a vector of ** data buffers to be treated as a single continuous buffer. CSM_VECTORs ** can be created in input or output mode. Input mode vectors are ** incapable of accepting data into an existing buffer. It is possible to ** add data to the end of the logical buffer simulated by input vectors. ** Output buffers are not able to append data to the end of a buffer. ** Instead, data is "flowed" into data buffers provided by the caller or ** into buffers allocated by the vector for the application. CSM_VECTORs ** should be deleted using the CSM_DeleteVector function. The structure of ** the CSM_VECTOR allows a CSP to simulate "encrypt-in-place" behavior. It ** does not support true encrypt-in-place behavior since the input vectors ** implicitly generate a temporary buffer when data is fetched from the ** vector. ** ** Parameters ** CSPHandle (input) - CSP handle that should be used to allocate memory ** that could possibly be returned to the calling application. ** pNewVector (input) - CSM_VECTOR structure to initialize. ** bInput (input) - Vector type. If CSSM_TRUE, then the vector behaves as ** an input vector, otherwise if behaves as an ouput vector. ** pNewBuffers (input) - Array of CSSM_DATA structures that are managed as ** a single logical buffer by the vector. ** uNumNewBuffers (input) - Number of CSSM_DATA structures referenced by ** pNewBuffers. ** pOverflow (input) - Pointer to a buffer that will be used to accept ** spill-over data from the main buffers in output vectors. ** ** Return Values ** CSSM_OK - The vector was initialized sucessfully. ** CSSMERR_CSP_INVALID_POINTER - The pNewVector or pNewBuffers pointers are ** NULL or the pStartData parameter is non-NULL for an output buffer. ** CSSMERR_CSP_INVALID_DATA - One of the input buffers is in a state that can ** not be reliably manipulated. Buffers must either have a non-NULL Data ** pointer with a non-zero Length, or have a NULL Data pointer with a ** zero Length. ** CSSMERR_CSP_MEMORY_ERROR - Memory could not be allocated to construct a ** composite buffer for an input vector. **------------------------------------------------------------------------- **/ CSSM_RETURN CSM_CreateVector( CSSM_CSP_HANDLE CSPHandle, CSM_VECTOR *pNewVector, CSSM_BOOL bInput, const CSSM_DATA *pNewBuffers, uint32 uNumNewBuffers, CSSM_DATA *pOverflow ) { CSSM_RETURN rv = CSSM_OK; CSSM_BOOL bAllowedToAllocate = CSSM_TRUE; uint32 Index; /* Parameter check */ if ( pNewVector == NULL ) { /* Nothing to operate on */ ERR( rv = CSSMERR_CSP_INVALID_POINTER ); } else if ( pNewBuffers == NULL ) { /* Must have input buffers */ ERR( rv = CSSMERR_CSP_INVALID_POINTER ); } else if ( ( bInput == CSSM_TRUE ) && ( pOverflow != NULL ) ) { /* An output vector can not have a start buffer */ ERR( rv = CSSMERR_CSP_INVALID_POINTER ); } else if ( ( pOverflow != NULL ) && ( ( rv = CSM_ValidateOutputBuffers( pOverflow, 1, CSSM_FALSE ) ) != CSSM_OK ) ) { /* Nothing required here */ } else { /* Check on the allocation state of the output buffers */ if ( !bInput ) { for ( Index = 0; Index < uNumNewBuffers; Index++ ) { /* See if we are passed any buffers and are allowed to allocate * memory for an output buffer. */ if ( pNewBuffers[Index].Data != NULL ) { bAllowedToAllocate = CSSM_FALSE; } } } /* Initilialize the structure */ memset( pNewVector, 0, sizeof(CSM_VECTOR) ); #ifdef _DEBUG pNewVector->__MagicNumber = __CSM_VECTOR_MAGIC_NUMBER; #endif pNewVector->bInputVector = bInput; pNewVector->CSPHandle = CSPHandle; pNewVector->Buffers = (CSSM_DATA*)pNewBuffers; pNewVector->uNumBuffers = uNumNewBuffers; pNewVector->bAllocateBuffers = bAllowedToAllocate; pNewVector->Overflow = pOverflow; pNewVector->bAllocatedOverflow = CSSM_FALSE; pNewVector->uIndex = 0; pNewVector->uOffset = 0; pNewVector->TempBuffer.Data = NULL; pNewVector->TempBuffer.Length = 0; /* If this is an input vector, create the composite buffer */ if ( bInput == CSSM_TRUE ) { rv = __CSM_CreateCompositeVectorBuffer( pNewVector ); } } /* Validation */ return rv; } /**------------------------------------------------------------------------- ** CSM_DeleteVector ** ** Description ** Uninitializes a CSM_VECTOR structure that was previously initialized ** with the CSM_CreateVector function. Temporary memory buffers are ** deallocated and if requested, the output buffers allocated for the ** application are deallocated. All buffers are wiped to zeros before ** deallocation. If the vector is an output buffer, the memory buffers ** were allocated by the vector, and the buffers are not being deallocated ** then the lengths of the output buffers will be adjusted to reflect the ** actual amount of data placed into the vector using the ** CSM_PopulateVector function. ** ** Parameters ** pVector (input) - CSM_VECTOR structure to uninitialize. ** bDeallocate (input) - Determines whether or not the data buffers for ** and output vector will be deallocated. The buffers will only be ** deallocated if the vector previously allocated them. ** ** Return Values ** CSSM_OK - The vector was uninitialized sucessfully. ** CSSMERR_CSP_INVALID_POINTER - The pVector pointer is NULL. **------------------------------------------------------------------------- **/ CSSM_RETURN CSM_DeleteVector( CSM_VECTOR *pVector, CSSM_BOOL bDeallocate ) { CSSM_RETURN rv = CSSM_OK; /* Parameter check */ ASSERT_VALID_CSM_VECTOR( pVector ); /* Only deallocate/manipulate output buffers */ if ( pVector->bInputVector == CSSM_FALSE ) { if ( bDeallocate == CSSM_TRUE ) { /* Did we allocate the data buffers */ if ( pVector->bAllocateBuffers == CSSM_TRUE ) { uint32 Index; for ( Index = 0; Index < pVector->uNumBuffers; Index++ ) { if ( pVector->Buffers[Index].Data != NULL ) { /* Wipe the buffer and deallocate it */ memset( pVector->Buffers[Index].Data, 0, pVector->Buffers[Index].Length ); MAF_FREE( pVector->CSPHandle, pVector->Buffers[Index].Data ); pVector->Buffers[Index].Data = NULL; } } } MAF_DeleteOutputBuffer( pVector->CSPHandle, pVector->Overflow, pVector->bAllocatedOverflow ); } /* Deallocate everything */ else { /* Don't deallocate; adjust values */ assert( ( pVector->uIndex == CSM_VECTOR_ATTEMPT_TO_OVERFILL ) || ( pVector->uIndex == CSM_VECTOR_OVERFLOW_BUFFER ) || ( pVector->uIndex < pVector->uNumBuffers ) ); if ( ( pVector->bAllocateBuffers == CSSM_TRUE ) && ( pVector->uIndex == CSM_VECTOR_OVERFLOW_BUFFER ) ) { /* All of the output vectors are full, the overflow * buffer might have something in it. */ if ( pVector->uOffset == 0 ) { /* Nothing in the output buffer. Deallocate the overflow * buffer if we allocated it. */ if ( pVector->Overflow ) { MAF_DeleteOutputBuffer( pVector->CSPHandle, pVector->Overflow, pVector->bAllocatedOverflow ); } } else { pVector->Overflow->Length = pVector->uOffset; } } else if ( pVector->bAllocateBuffers == CSSM_TRUE ) { /* The vector allocated the output buffers, but they * weren't completely filled. */ if ( pVector->uIndex < pVector->uNumBuffers ) { /* Update the length of the output buffers to match the * actual data lengths in the buffers. */ pVector->Buffers[pVector->uIndex].Length = pVector->uOffset; /* If there is an overflow buffer, set the length to * zero. No need to possibly deallocate it because the * vector would not have attempted to allocate it. */ if ( pVector->Overflow ) { pVector->Overflow->Length = 0; } } else { ERR( rv = CSSMERR_CSP_INTERNAL_ERROR ); assert( 0 ); /* This should NEVER happen */ } } else if ( pVector->uIndex == CSM_VECTOR_OVERFLOW_BUFFER ) { /* Adjust the overflow buffer to match the amount of data inside */ if ( pVector->uOffset == 0 ) { MAF_DeleteOutputBuffer( pVector->CSPHandle, pVector->Overflow, pVector->bAllocatedOverflow ); if ( pVector->Overflow ) { pVector->Overflow->Length = 0; } } else { pVector->Overflow->Length = pVector->uOffset; } } else if ( pVector->uIndex != CSM_VECTOR_ATTEMPT_TO_OVERFILL ) { /* If there is an overflow buffer, deallocate it (if * allocated) and set the length to zero. */ if ( pVector->Overflow != NULL ) { MAF_DeleteOutputBuffer( pVector->CSPHandle, pVector->Overflow, pVector->bAllocatedOverflow ); pVector->Overflow->Length = 0; } } /* We don't need an else case to handle the state where * Index==CSM_VECTOR_ATTEMPT_TO_OVERFILL because no length * adjustements are necessary. All buffers are filled to * capacity. */ } /* Don't deallocate; adjust values */ } /* Output vector */ else { /* Input vector */ /* Anything in the TempBuffer values were allocated by us */ if ( pVector->TempBuffer.Data != NULL ) { /* Wipe the buffer and deallocate it */ memset( pVector->TempBuffer.Data, 0, pVector->TempBuffer.Length ); Addin_free( pVector->TempBuffer.Data, NULL ); } } /* Input vector */ /* Wipe the vector structure */ memset( pVector, 0, sizeof(CSM_VECTOR) ); return rv; } /**------------------------------------------------------------------------- ** CSM_GetVectorLength ** ** Description ** Returns the length of the single logical buffer simulated by the ** vector. The returned value will include the length of any data appended ** to the logical buffer for input buffers. The returned value will ** include the total space represented by an output buffer including the ** overflow buffer. If the application wants the addin to allocate the ** return buffers, then the returned length may be zero if the ** CSM_GuaranteeVectorSpace function has not been called. ** ** Parameters ** pVector (input) - CSM_VECTOR structure to interrogate. ** puLength (output) - Pointer to the variable that will receive the ** total length of the vector. ** ** Return Values ** CSSM_OK - The length was sucessfully calculated. ** CSSMERR_CSP_INVALID_POINTER - The pVector or puLength pointer is NULL. **------------------------------------------------------------------------- **/ CSSM_RETURN CSM_GetVectorLength( const CSM_VECTOR *pVector, uint32 *puLength ) { uint32 uTotalLength = 0; uint32 Index; /* Parameter check */ assert( puLength ); ASSERT_VALID_CSM_VECTOR( pVector ); /* Total up the lengths of the StartData and Buffers */ if ( ( pVector->bInputVector == CSSM_TRUE ) && ( pVector->TempBuffer.Data != NULL ) ) { /* Return the composit length that is already known */ uTotalLength = pVector->TempBuffer.Length; } else { /* Either the composit input buffer has not been generated or this * is an output buffer. */ for ( Index = 0; Index < pVector->uNumBuffers; Index++ ) { uTotalLength += pVector->Buffers[Index].Length; } if ( pVector->Overflow != NULL ) { uTotalLength += pVector->Overflow->Length; } } /* Set the return parameters */ *puLength = uTotalLength; return CSSM_OK; } /**------------------------------------------------------------------------- ** CSM_GetVectorIndex ** ** Description ** Returns the logical index into the vector. This may not have any ** correspondence to actual buffers in the CSM_VECTOR structure. For input ** vectors, this is the location in the logical buffer from which the next ** set of data requested using the CSM_GetBlockLengthVectorBuffer or ** CSM_FetchExtraVectorData fucntions will originate. For output vectors, ** this is the insertion point in the logical buffer where new data will ** be placed using the CSM_PopulateVector function. The remaining data in ** an input vector of the "free" space in an output vector can be found by ** subtracting the result of this function from the result of the ** CSM_GetVectorLength function. ** ** Parameters ** pVector (input) - CSM_VECTOR structure to interrogate. ** puCurrentIndex (output) - Pointer to the variable that will receive the ** current index of the vector. ** ** Return Values ** CSSM_OK - The index was sucessfully calculated. ** CSSMERR_CSP_INVALID_POINTER - The pVector or puCurrentIndex pointer is ** NULL. **------------------------------------------------------------------------- **/ CSSM_RETURN CSM_GetVectorIndex( const CSM_VECTOR *pVector, uint32 *puCurrentIndex ) { CSSM_RETURN rv = CSSM_OK; uint32 uCurrentIndex = 0; uint32 Index; uint32 TopIndex; /* Parameter check */ ASSERT_VALID_CSM_VECTOR( pVector ); /* Total up the lengths of the StartData and Buffers */ if ( port_IsBadWritePtr( puCurrentIndex, sizeof(*puCurrentIndex) ) ) { ERR( rv = CSSMERR_CSP_INVALID_OUTPUT_POINTER ); } else if ( pVector->bInputVector == CSSM_FALSE ) { if ( ( pVector->uIndex == CSM_VECTOR_OVERFLOW_BUFFER ) || ( pVector->uIndex == CSM_VECTOR_ATTEMPT_TO_OVERFILL ) ) { TopIndex = pVector->uNumBuffers; } else { TopIndex = pVector->uIndex; } /* Don't include the current buffer */ for ( Index = 0; Index < TopIndex; Index++ ) { uCurrentIndex += pVector->Buffers[Index].Length; } /* If the index is ATTEMPT_TO_OVERFILL, add the total length of * the overflow buffer to the length, otherwise add the offset. */ if ( pVector->uIndex == CSM_VECTOR_ATTEMPT_TO_OVERFILL ) { if ( pVector->Overflow != NULL ) { uCurrentIndex += pVector->Overflow->Length; } } else { uCurrentIndex += pVector->uOffset; } } else { uCurrentIndex = pVector->uOffset; } /* Set the return parameters */ *puCurrentIndex = uCurrentIndex; return rv; } /**------------------------------------------------------------------------- ** CSM_GetVectorSize ** ** Description ** Returns the actual number of valid CSSM_DATA buffers in the vector. ** This may be different that the number of buffers passed to the ** CSM_CreateVector function. The result includes the overflow data given ** during vector creation, but will not include data appended to the end ** of an input buffer. ** ** Parameters ** pVector (input) - CSM_VECTOR structure to interrogate. ** puSize (output) - Pointer to the variable that will receive the size of ** the vector. ** ** Return Values ** CSSM_OK - The size was sucessfully calculated. ** CSSMERR_CSP_INVALID_POINTER - The pVector or puSize pointer is NULL. **------------------------------------------------------------------------- **/ CSSM_RETURN CSM_GetVectorSize( const CSM_VECTOR *pVector, uint32 *puSize ) { uint32 uTotalSize = 0; uint32 Index; /* Parameter check */ assert( puSize ); ASSERT_VALID_CSM_VECTOR( pVector ); /* Total up the lengths of the StartData, Buffers and EndData */ for ( Index = 0; Index < pVector->uNumBuffers; Index++ ) { if ( pVector->Buffers[Index].Data != NULL ) { uTotalSize ++; } } if ( ( pVector->Overflow != NULL ) && ( pVector->Overflow->Data != NULL ) ) { uTotalSize++; } /* Set the return parameters */ *puSize = uTotalSize; return CSSM_OK; } /**------------------------------------------------------------------------- ** CSM_GuaranteeVectorSpace ** ** Description ** This function will attempt to insure that the requested space is ** available in an output vector. The function will assert an error if an ** input vector is specified. If output buffers were specified by the ** caller, then a check is made to see that at least the required amount ** of space is available. If there is not enough space, the function ** fails. The the caller did not give output buffers, a single output ** buffer of the size requested is allocated and assigned to the first ** CSSM_DATA structure maintained by the vector. This memory is allocated ** using the MAF MAF_MALLOC function and the CSP handle specified during ** vector creation. ** ** Parameters ** pVector (input) - CSM_VECTOR structure to interrogate. ** uNeedSpace (input) - Number of bytes that are required in the output ** buffer. ** ** Return Values ** CSSM_OK - The vector has space for at least uNeedSize bytes. ** CSSMERR_CSP_INVALID_POINTER - The pVector pointer is NULL. ** CSSM_CSP_ERR_OUTBUF_LENGTH - The caller specified output buffers that ** did not provide space for uNeedSpace bytes of data. ** CSSMERR_CSP_MEMORY_ERROR - The caller did not provide output buffers and ** uNeedBytes of memory could not be allocated from the application. ** CSSMERR_CSP_INTERNAL_ERROR - The CSSM_DATA structures are in a state that ** is prevented by the CSM_CreateVector function, but the data has been ** corrupted. **------------------------------------------------------------------------- **/ CSSM_RETURN CSM_GuaranteeVectorSpace( CSM_VECTOR *pVector, uint32 uNeedSpace ) { CSSM_RETURN rv = CSSM_OK; uint32 uCurrentSpace = 0; /* Parameter check */ assert( pVector ); ASSERT_VALID_CSM_VECTOR( pVector ); /* The vector must be an output vector */ assert( pVector->bInputVector == CSSM_FALSE ); /* If the output buffers are empty, allocate a buffer large enough to * meet the length requirement. Ignore the overflow buffer in this * case. */ if ( pVector->bAllocateBuffers == CSSM_TRUE ) { pVector->Buffers[0].Data = MAF_MALLOC( pVector->CSPHandle, uNeedSpace ); if ( pVector->Buffers[0].Data == NULL ) { ERR( rv = CSSMERR_CSP_MEMORY_ERROR ); } else { pVector->Buffers[0].Length = uNeedSpace; } } else { /* How big is the current set of buffers */ if ( ( rv = CSM_GetVectorLength( pVector, &uCurrentSpace ) ) == CSSM_OK ) { /* Do we have enough space? */ if ( uCurrentSpace < uNeedSpace ) { /* If the overflow buffer exists and is empty, allocate * the difference between the required length and the * space in the supplied buffers. */ if ( ( pVector->Overflow != NULL ) && ( pVector->Overflow->Data == NULL ) ) { pVector->Overflow->Length = 0; /* Ensure an empty buffer */ rv = MAF_CreateOutputBuffer( pVector->CSPHandle, ( uNeedSpace - uCurrentSpace ), pVector->Overflow, &pVector->bAllocatedOverflow ); } else { /* Not enough output space, and nothing we can do * about it. */ ERR( rv = CSSMERR_CSP_OUTPUT_LENGTH_ERROR ); } } } } return rv; } /**------------------------------------------------------------------------- ** CSM_AppendVectorData ** ** Description ** Appends the supplied data to the end of the logical buffer simulated by ** the CSM_VECTOR. The new data is included in the values returned by ** the CSM_GetVectorLength function, but is not stored in a manner that ** allows retrieval of the new data by itself. This function may be called ** multiple times on a single input vector. This function can not be used ** on output vectors. If a memory error is reported, the CSM_VECTOR is ** left in the same state that it was in before the call to ** CSM_AppendVectorData. ** ** Parameters ** pVector (input) - CSM_VECTOR structure to manipulate. ** pNewData (input) - Buffer containing the data to add to the logical ** buffer. ** ** Return Values ** CSSM_OK - Data was sucessfully added to the vector. ** CSSMERR_CSP_INVALID_POINTER - The pVector or pNewData pointer is NULL. ** CSSMERR_CSP_MEMORY_ERROR - The required memory could not be allocated to ** store the new data. The state of the CSM_VECTOR is not effected by ** this error. **------------------------------------------------------------------------- **/ CSSM_RETURN CSM_AppendVectorData( CSM_VECTOR *pVector, const CSSM_DATA *pNewData ) { CSSM_RETURN rv = CSSM_OK; uint8* pTempBuf = NULL; /* Parameter check */ assert( pNewData ); ASSERT_VALID_CSM_VECTOR( pVector ); /* Must use CSM_AppendVectorData to append input buffers */ assert( pVector->bInputVector == CSSM_TRUE ); /* Is this a zero length buffer? */ if ( pNewData->Length > 0 ) { /* Do we already have data in the end vector? */ if ( pVector->TempBuffer.Data != NULL ) { /* Reallocate a bigger buffer and copy in the new data */ pTempBuf = Addin_realloc( pVector->TempBuffer.Data, pVector->TempBuffer.Length + pNewData->Length, NULL ); if ( pTempBuf == NULL ) { ERR( rv = CSSMERR_CSP_MEMORY_ERROR ); } else { pVector->TempBuffer.Data = pTempBuf; memcpy( &pVector->TempBuffer.Data[pVector->TempBuffer.Length], pNewData->Data, pNewData->Length ); pVector->TempBuffer.Length += pNewData->Length; } } else { /* Allocate a buffer and copy the data buffer */ pVector->TempBuffer.Data = Addin_malloc( pNewData->Length, NULL ); if ( pVector->TempBuffer.Data == NULL ) { ERR( rv = CSSMERR_CSP_MEMORY_ERROR ); } else { pVector->TempBuffer.Length = pNewData->Length; memcpy( pVector->TempBuffer.Data, pNewData->Data, pNewData->Length ); } } } return rv; } /**------------------------------------------------------------------------- ** CSM_GetVectorBuffer ** ** Description ** Returns a copy of the CSSM_DATA structure indicated by the BufferIndex ** parameter. ** ** Parameters ** pVector (input) - CSM_VECTOR structure to interrogate. ** BufferIndex (input) - Zero based index of the CSSM_DATA structure to ** return. The value must be in the range of zero to the number of ** buffers passed to the CSM_CreateVector function. If the parameter ** value is CSM_VECTOR_START_BUFFER, then the buffer given as the ** pStartData parameter to the CSM_CreateVector function is returned. ** pBuffer (output) - Pointer to the variable that will receive the copy ** of the CSSM_DATA structure requested. ** ** Return Values ** CSSM_OK - The requested buffer has been returned. ** CSSMERR_CSP_INVALID_POINTER - The pVector or pBuffer pointer is NULL. ** MAFR_VALUE_RANGE - The requested buffer does not exist. **------------------------------------------------------------------------- **/ CSSM_RETURN CSM_GetVectorBuffer( const CSM_VECTOR *pVector, uint32 BufferIndex, CSSM_DATA *pBuffer ) { CSSM_RETURN rv = CSSM_OK; /* Parameter check */ assert( pBuffer ); ASSERT_VALID_CSM_VECTOR( pVector ); /* Find the correct buffer and return a copy of the CSSM_DATA */ if ( BufferIndex == CSM_VECTOR_OVERFLOW_BUFFER ) { *pBuffer = *pVector->Overflow; } else if ( BufferIndex < pVector->uNumBuffers ) { *pBuffer = pVector->Buffers[BufferIndex]; } else { assert( 0 ); ERR( rv = CSMR_VALUE_RANGE ); } return rv; } /**------------------------------------------------------------------------- ** CSM_GetBlockLengthVectorBuffer ** ** Description ** Returns a CSSM_DATA variable that references a continuous buffer with ** a length that is a multiple of the uBlockSize parameter. This buffer ** may contain fewer bytes than the contents of the vector. The result ** buffer may or may not be the largest buffer that can be returned from ** the vector. The function can be called repeatedly until the return ** code is MAFR_NO_MORE_DATA to get all of the data. The buffer returned ** is owned by the vector and must not be deallocated by the caller. The ** logical index in the vector is incremented by the length of the result ** buffer. Only input vectors may use this function. ** ** Parameters ** pVector (input) - CSM_VECTOR structure to interrogate. ** uBlockSize (input) - The length of the output buffer will be a multiple ** of this value. It may not be zero. ** pBuffer (output) - Pointer to the variable that will receive a buffer ** with the requested data. ** ** Return Values ** CSSM_OK - Data was sucessfully fetched from the vector. ** MAFR_NO_MORE_DATA - A buffer with a minimum length of uBlockSize can ** not be returned. Call the function with a block size of one to fetch ** the rest of the data if you don't require ownership of the result. ** CSSMERR_CSP_INVALID_POINTER - The pVector or pBuffer pointer is NULL. ** MAFR_VALUE_RANGE - The uBlockSize parameter if not valid. **------------------------------------------------------------------------- **/ CSSM_RETURN CSM_GetBlockLengthVectorBuffer( CSM_VECTOR *pVector, uint32 uBlockSize, CSSM_DATA *pBuffer ) { CSSM_RETURN rv = CSSM_OK; /* Parameter check */ assert( pBuffer ); assert( uBlockSize > 0 ); ASSERT_VALID_CSM_VECTOR( pVector ); /* Must be an input vector to fetch block length data */ assert( pVector->bInputVector == CSSM_TRUE ); /* Is there any more data to return? */ if ( ( pVector->TempBuffer.Length - pVector->uOffset ) < uBlockSize ) { ERR( rv = CSMR_NO_MORE_DATA ); } else { /* Multiple-block return */ pBuffer->Data = &pVector->TempBuffer.Data[pVector->uOffset]; pBuffer->Length = ( ( pVector->TempBuffer.Length - pVector->uOffset ) / uBlockSize ) * uBlockSize; pVector->uOffset += pBuffer->Length; assert( pVector->uOffset <= pVector->TempBuffer.Length ); } return rv; } /**------------------------------------------------------------------------- ** CSM_FetchExtraVectorData ** ** Description ** Returns a CSSM_DATA variable that references a continuous buffer ** containing all data in the vector after the current logical index. The ** buffer is owned by the caller and will not be tracked by the vector. ** Memory allocated for this purpose is allocated using the Addin_malloc ** function with an AllocRef of NULL. If there is no data remaining after ** the logical index, no memory is allocated and the return value contains ** a NULL Data member and a Length value of zero. The logical index into ** the vector is not effected by this function. Only input vectors may use ** this function. ** ** Parameters ** pVector (input) - CSM_VECTOR structure to interrogate. ** pBuffer (output) - Pointer to the variable that will receive a buffer ** with the requested data. ** ** Return Values ** CSSM_OK - Data was sucessfully fetched from the vector. ** CSSMERR_CSP_INVALID_POINTER - The pVector or pBuffer pointer is NULL. ** CSSMERR_CSP_MEMORY_ERROR - Memory could not be allocated to return the ** requested data. **------------------------------------------------------------------------- **/ CSSM_RETURN CSM_FetchExtraVectorData( CSM_VECTOR *pVector, CSSM_DATA *pBuffer ) { CSSM_RETURN rv = CSSM_OK; /* Parameter check */ assert( pBuffer ); ASSERT_VALID_CSM_VECTOR( pVector ); /* Must be an input vector to fetch block length data */ assert( pVector->bInputVector == CSSM_TRUE ); /* Allocate a buffer big enough to hold the extra data. If all of the * data has been consumed, then the return value will be a NULL buffer. */ if ( pVector->uOffset == pVector->TempBuffer.Length ) { pBuffer->Data = NULL; pBuffer->Length = 0; } else { pBuffer->Length = pVector->TempBuffer.Length - pVector->uOffset; pBuffer->Data = Addin_malloc( pBuffer->Length, NULL ); if ( pBuffer->Data == NULL ) { pBuffer->Length = 0; ERR( rv = CSSMERR_CSP_MEMORY_ERROR ); } } return rv; } /**------------------------------------------------------------------------- ** CSM_PopulateVector ** ** Description ** "Flows" the data contained in the pNewData buffer into the logical ** buffer simulated by the vector. Data is placed in each buffer in turn ** until that buffer is full. The next valid buffer is then found to ** receive the next bit of data. This process repeats until all of the ** data has been placed into the output buffers. If built with the _DEBUG ** compiler symbol, a check will be made to insure that there is enough ** space remaining in the vector to accomodate the new data. The ** CSM_GuaranteeVectorSpace function should always be called before ** attempting to add data to the vector. The logical index into the vector ** is incremented by the number of bytes added to the vector. Only output ** vectors may use this function. ** ** Parameters ** pVector (input) - CSM_VECTOR structure to update. ** pNewData (output) - A buffer containing new data to place into the ** vector buffers. ** ** Return Values ** CSSM_OK - Data was sucessfully fetched from the vector. ** CSSMERR_CSP_INVALID_POINTER - The pVector or pNewData pointer is NULL. ** CSSMERR_CSP_INVALID_DATA - The pNewData buffer is NULL. **------------------------------------------------------------------------- **/ CSSM_RETURN CSM_PopulateVector( CSM_VECTOR *pVector, const CSSM_DATA *pNewData ) { CSSM_RETURN rv = CSSM_OK; uint32 uInputIndex = 0; uint32 uRemainingBytes; uint32 uSpaceInBuffer; CSSM_DATA *pFillBuf = NULL; /* Parameter check */ assert( pNewData ); assert( pNewData->Data ); ASSERT_VALID_CSM_VECTOR( pVector ); /* Must be an output vector to insert data */ assert( pVector->bInputVector == CSSM_FALSE ); #ifdef _DEBUG { uint32 uTotalLength = 0; uint32 uCurrentIndex = 0; /* Perform a check to see that there is enough space in the vector */ if ( ( ( rv = CSM_GetVectorLength( pVector, &uTotalLength ) ) != CSSM_OK ) || ( ( rv = CSM_GetVectorIndex( pVector, &uCurrentIndex ) ) != CSSM_OK ) ) { return rv; } /* Fault execution if the caller attempts to fill the vector with * too much data. */ assert( ( uTotalLength - uCurrentIndex ) >= pNewData->Length ); } #endif /* Start filling the buffers starting from the current index position. * Each buffer will be filled completely before placing anything in * the next buffer. */ while ( uInputIndex < pNewData->Length ) { /* This assertion will trigger if an attempt is made to fill * the vector past capacity when the vector is already completely * full. */ assert( ( pVector->uIndex < pVector->uNumBuffers ) || ( pVector->uIndex == CSM_VECTOR_OVERFLOW_BUFFER ) ); if ( pVector->uIndex == CSM_VECTOR_ATTEMPT_TO_OVERFILL ) { ERR( rv = CSSMERR_CSP_INTERNAL_ERROR ); break; } /* Set the buffer to fill */ if ( pVector->uIndex < pVector->uNumBuffers ) { pFillBuf = &pVector->Buffers[pVector->uIndex]; } else { pFillBuf = pVector->Overflow; } assert( pFillBuf ); /* Calculate the source and destination length */ uRemainingBytes = pNewData->Length - uInputIndex; uSpaceInBuffer = pFillBuf->Length - pVector->uOffset; assert( uSpaceInBuffer > 0 ); /* Determine how to copy the data */ if ( uRemainingBytes <= uSpaceInBuffer ) { /* The rest of the data can be copied */ memcpy( &pFillBuf->Data[pVector->uOffset], &pNewData->Data[uInputIndex], uRemainingBytes ); pVector->uOffset += uRemainingBytes; uInputIndex += uRemainingBytes; } else { memcpy( &pFillBuf->Data[pVector->uOffset], &pNewData->Data[uInputIndex], uSpaceInBuffer ); pVector->uOffset += uSpaceInBuffer; uInputIndex += uSpaceInBuffer; } /* Adjust the index pointer if necessary */ if ( pVector->uOffset == pFillBuf->Length ) { /* Set the offset to zero */ pVector->uOffset = 0; /* Set overfill detection */ if ( pVector->uIndex == CSM_VECTOR_OVERFLOW_BUFFER ) { pVector->uIndex = CSM_VECTOR_ATTEMPT_TO_OVERFILL; /* Determine if this is an error or not */ if ( uInputIndex < pNewData->Length ) { /* Error: full vector with more data to put in it */ ERR( rv = CSSMERR_CSP_INTERNAL_ERROR ); } else { /* OK: the vector is full without any data left. * calling PopulateVector again is an error. */ break; } } /* Find the next available buffer */ while ( rv == CSSM_OK ) { /* The caller didn't calculate the outputs very well and * overflowed the vector, including the overflow buffer! */ assert( pVector->uIndex != CSM_VECTOR_OVERFLOW_BUFFER ); if ( pVector->uIndex == CSM_VECTOR_OVERFLOW_BUFFER ) { ERR( rv = CSSMERR_CSP_INTERNAL_ERROR ); } else { pVector->uIndex++; if ( pVector->uIndex == pVector->uNumBuffers ) { /* This is the last buffer, set the index to the * overflow buffer. */ pVector->uIndex = CSM_VECTOR_OVERFLOW_BUFFER; break; } else { /* Is this buffer usable? */ if ( ( pVector->Buffers[pVector->uIndex].Data != NULL ) && ( pVector->Buffers[pVector->uIndex].Length != 0 ) ) { /* Use this buffer. */ break; } } } } /* end while */ } /* end if */ } /* end while */ return rv; }