1cf2cfa174ca878c144e17e9fc60ca8e9070d7dededisonn@google.com/*---------------------------------------------------------------------------*
2cf2cfa174ca878c144e17e9fc60ca8e9070d7dededisonn@google.com *  CircularBuffer.c  *
3cf2cfa174ca878c144e17e9fc60ca8e9070d7dededisonn@google.com *                                                                           *
4cf2cfa174ca878c144e17e9fc60ca8e9070d7dededisonn@google.com *  Copyright 2007, 2008 Nuance Communciations, Inc.                               *
5cf2cfa174ca878c144e17e9fc60ca8e9070d7dededisonn@google.com *                                                                           *
6cf2cfa174ca878c144e17e9fc60ca8e9070d7dededisonn@google.com *  Licensed under the Apache License, Version 2.0 (the 'License');          *
7cf2cfa174ca878c144e17e9fc60ca8e9070d7dededisonn@google.com *  you may not use this file except in compliance with the License.         *
8cf2cfa174ca878c144e17e9fc60ca8e9070d7dededisonn@google.com *                                                                           *
9cf2cfa174ca878c144e17e9fc60ca8e9070d7dededisonn@google.com *  You may obtain a copy of the License at                                  *
108cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com *      http://www.apache.org/licenses/LICENSE-2.0                           *
118cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com *                                                                           *
128cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com *  Unless required by applicable law or agreed to in writing, software      *
138cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com *  distributed under the License is distributed on an 'AS IS' BASIS,        *
148cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. *
158cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com *  See the License for the specific language governing permissions and      *
168cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com *  limitations under the License.                                           *
178cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com *                                                                           *
188cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com *---------------------------------------------------------------------------*/
198cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com
208cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com
218cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com
228cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com#ifdef _WIN32
238cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com#if _MSC_VER >= 1100    // Visual C++ 5.x
248cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com#pragma warning( disable : 4786 4503 )
258cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com#endif
268cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com#endif
278cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com
288cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com#include "CircularBuffer.h"
298cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com#include "pmemory.h"
308cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com#ifndef __vxworks
318cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com#include <memory.h>
328cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com#endif
338cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com
348cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.comESR_ReturnCode CircularBufferCreate(size_t capacity, const LCHAR* mtag, CircularBuffer** buffer)
358cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com{
368cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com  CircularBuffer* Interface;
378cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com  if (buffer == NULL || capacity <= 0)
388cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com    return ESR_INVALID_ARGUMENT;
398cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com
408cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com  Interface = (CircularBuffer *) MALLOC(sizeof(CircularBuffer) + capacity, mtag);
418cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com  if (Interface == NULL)
428cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com    return ESR_OUT_OF_MEMORY;
438cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com  Interface->capacity = capacity;
448cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com  CircularBufferReset(Interface);
458cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com  *buffer = Interface;
468cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com  return ESR_SUCCESS;
478cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com}
488cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com
498cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com
508cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.comint CircularBufferRead(CircularBuffer* buffer, void* data, size_t bufSize)
518cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com{
528cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com  size_t nbRead = 0;
538cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com  unsigned char *bufferData = NULL;
548cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com
558cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com  if (buffer == NULL || (data == NULL && bufSize > 0))
568cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com    return -1;
578cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com
588cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com  if (buffer->size < bufSize)
598cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com    bufSize = buffer->size;
608cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com
618cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com  if (bufSize == 0)
628cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com    return 0;
638cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com
648cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com  bufferData = ((unsigned char *) buffer) + sizeof(CircularBuffer);
658cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com
668cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com  if (buffer->readIdx >= buffer->writeIdx)
678cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com  {
688cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com    nbRead = buffer->capacity - buffer-> readIdx;
698cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com    if (nbRead > bufSize) nbRead = bufSize;
708cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com
718cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com    memcpy(data, bufferData + buffer->readIdx, nbRead);
728cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com    buffer->size -= nbRead;
738cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com    buffer->readIdx += nbRead;
748cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com    if (buffer->readIdx == buffer->capacity)
758cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com      buffer->readIdx = 0;
768cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com  }
778cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com
788cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com  if (nbRead < bufSize)
798cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com  {
808cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com    int toRead = bufSize - nbRead;
818cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com    memcpy(((unsigned char *) data) + nbRead, bufferData + buffer->readIdx, toRead);
828cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com    buffer->size -= toRead;
838cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com    buffer->readIdx += toRead;
848cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com  }
858cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com
868cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com  return bufSize;
878cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com}
888cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com
898cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.comint CircularBufferSkip(CircularBuffer* buffer, size_t bufSize)
908cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com{
918cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com  if ( buffer == NULL )
928cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com    return -1;
938cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com
948cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com  if (buffer->size < bufSize)
958cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com    bufSize = buffer->size;
968cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com
978cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com  if (bufSize == 0)
988cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com    return 0;
998cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com
1008cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com  buffer->readIdx += bufSize;
1018cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com  if (buffer->readIdx >= buffer->capacity)
1028cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com    buffer->readIdx -= buffer->capacity;
1038cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com
1048cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com  buffer->size -= bufSize;
1058cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com
1068cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com  return bufSize;
1078cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com}
1088cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com
1098cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.comint CircularBufferWrite(CircularBuffer* buffer, const void *data, size_t bufSize)
1108cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com{
1118cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com  size_t nbWritten = 0;
1128cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com  unsigned char *bufferData;
1138cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com  size_t available = buffer->capacity - buffer->size;
1148cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com
1158cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com  if (data == NULL && bufSize > 0)
1168cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com    return -1;
1178cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com
1188cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com  if (available < bufSize)	/* We need to force an error to be logged here */
1198cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com    return -1;
1208cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com/*    bufSize = available;	Throwing data on the floor with no notice is asking for trouble */
1218cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com
1228cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com  if (bufSize == 0)
1238cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com    return 0;
1248cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com
1258cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com  bufferData = ((unsigned char*) buffer) + sizeof(CircularBuffer);
1268cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com
1278cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com  if (buffer->writeIdx >= buffer->readIdx)
1288cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com  {
1298cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com    nbWritten = buffer->capacity - buffer->writeIdx;
1308cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com    if (nbWritten > bufSize) nbWritten = bufSize;
1318cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com    memcpy(bufferData + buffer->writeIdx, data, nbWritten);
1328cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com    buffer->size += nbWritten;
1338cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com    buffer->writeIdx += nbWritten;
1348cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com    if (buffer->writeIdx == buffer->capacity)
1358cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com      buffer->writeIdx = 0;
1368cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com  }
1378cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com
1388cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com  if (nbWritten < bufSize)
1398cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com  {
1408cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com    size_t toWrite = bufSize - nbWritten;
1418cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com    memcpy(bufferData + buffer->writeIdx, ((unsigned char*) data) + nbWritten, toWrite);
1428cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com    buffer->size += toWrite;
1438cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com    buffer->writeIdx += toWrite;
1448cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com  }
1458cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com
1468cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com  return bufSize;
1478cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com}
1488cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com
1498cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.comint CircularBufferUnwrite(CircularBuffer* buffer, size_t amount)
1508cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com{
1518cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com  size_t available = buffer->capacity - buffer->size;
1528cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com
1538cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com  if (available < amount)
1548cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com    amount = available;
1558cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com  buffer->size -= amount;
1568cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com  return amount;
1578cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com}
1588cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com