1/*---------------------------------------------------------------------------*
2 *  CircularBuffer.c  *
3 *                                                                           *
4 *  Copyright 2007, 2008 Nuance Communciations, Inc.                               *
5 *                                                                           *
6 *  Licensed under the Apache License, Version 2.0 (the 'License');          *
7 *  you may not use this file except in compliance with the License.         *
8 *                                                                           *
9 *  You may obtain a copy of the License at                                  *
10 *      http://www.apache.org/licenses/LICENSE-2.0                           *
11 *                                                                           *
12 *  Unless required by applicable law or agreed to in writing, software      *
13 *  distributed under the License is distributed on an 'AS IS' BASIS,        *
14 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. *
15 *  See the License for the specific language governing permissions and      *
16 *  limitations under the License.                                           *
17 *                                                                           *
18 *---------------------------------------------------------------------------*/
19
20
21
22#ifdef _WIN32
23#if _MSC_VER >= 1100    // Visual C++ 5.x
24#pragma warning( disable : 4786 4503 )
25#endif
26#endif
27
28#include "CircularBuffer.h"
29#include "pmemory.h"
30#ifndef __vxworks
31#include <memory.h>
32#endif
33
34ESR_ReturnCode CircularBufferCreate(size_t capacity, const LCHAR* mtag, CircularBuffer** buffer)
35{
36  CircularBuffer* Interface;
37  if (buffer == NULL || capacity <= 0)
38    return ESR_INVALID_ARGUMENT;
39
40  Interface = (CircularBuffer *) MALLOC(sizeof(CircularBuffer) + capacity, mtag);
41  if (Interface == NULL)
42    return ESR_OUT_OF_MEMORY;
43  Interface->capacity = capacity;
44  CircularBufferReset(Interface);
45  *buffer = Interface;
46  return ESR_SUCCESS;
47}
48
49
50int CircularBufferRead(CircularBuffer* buffer, void* data, size_t bufSize)
51{
52  size_t nbRead = 0;
53  unsigned char *bufferData = NULL;
54
55  if (buffer == NULL || (data == NULL && bufSize > 0))
56    return -1;
57
58  if (buffer->size < bufSize)
59    bufSize = buffer->size;
60
61  if (bufSize == 0)
62    return 0;
63
64  bufferData = ((unsigned char *) buffer) + sizeof(CircularBuffer);
65
66  if (buffer->readIdx >= buffer->writeIdx)
67  {
68    nbRead = buffer->capacity - buffer-> readIdx;
69    if (nbRead > bufSize) nbRead = bufSize;
70
71    memcpy(data, bufferData + buffer->readIdx, nbRead);
72    buffer->size -= nbRead;
73    buffer->readIdx += nbRead;
74    if (buffer->readIdx == buffer->capacity)
75      buffer->readIdx = 0;
76  }
77
78  if (nbRead < bufSize)
79  {
80    int toRead = bufSize - nbRead;
81    memcpy(((unsigned char *) data) + nbRead, bufferData + buffer->readIdx, toRead);
82    buffer->size -= toRead;
83    buffer->readIdx += toRead;
84  }
85
86  return bufSize;
87}
88
89int CircularBufferSkip(CircularBuffer* buffer, size_t bufSize)
90{
91  if ( buffer == NULL )
92    return -1;
93
94  if (buffer->size < bufSize)
95    bufSize = buffer->size;
96
97  if (bufSize == 0)
98    return 0;
99
100  buffer->readIdx += bufSize;
101  if (buffer->readIdx >= buffer->capacity)
102    buffer->readIdx -= buffer->capacity;
103
104  buffer->size -= bufSize;
105
106  return bufSize;
107}
108
109int CircularBufferWrite(CircularBuffer* buffer, const void *data, size_t bufSize)
110{
111  size_t nbWritten = 0;
112  unsigned char *bufferData;
113  size_t available = buffer->capacity - buffer->size;
114
115  if (data == NULL && bufSize > 0)
116    return -1;
117
118  if (available < bufSize)	/* We need to force an error to be logged here */
119    return -1;
120/*    bufSize = available;	Throwing data on the floor with no notice is asking for trouble */
121
122  if (bufSize == 0)
123    return 0;
124
125  bufferData = ((unsigned char*) buffer) + sizeof(CircularBuffer);
126
127  if (buffer->writeIdx >= buffer->readIdx)
128  {
129    nbWritten = buffer->capacity - buffer->writeIdx;
130    if (nbWritten > bufSize) nbWritten = bufSize;
131    memcpy(bufferData + buffer->writeIdx, data, nbWritten);
132    buffer->size += nbWritten;
133    buffer->writeIdx += nbWritten;
134    if (buffer->writeIdx == buffer->capacity)
135      buffer->writeIdx = 0;
136  }
137
138  if (nbWritten < bufSize)
139  {
140    size_t toWrite = bufSize - nbWritten;
141    memcpy(bufferData + buffer->writeIdx, ((unsigned char*) data) + nbWritten, toWrite);
142    buffer->size += toWrite;
143    buffer->writeIdx += toWrite;
144  }
145
146  return bufSize;
147}
148
149int CircularBufferUnwrite(CircularBuffer* buffer, size_t amount)
150{
151  size_t available = buffer->capacity - buffer->size;
152
153  if (available < amount)
154    amount = available;
155  buffer->size -= amount;
156  return amount;
157}
158