1
2/*
3* Copyright 2010-2017 Amazon.com, Inc. or its affiliates. All Rights Reserved.
4*
5* Licensed under the Apache License, Version 2.0 (the "License").
6* You may not use this file except in compliance with the License.
7* A copy of the License is located at
8*
9* http://aws.amazon.com/apache2.0
10*
11* or in the "license" file accompanying this file. This file is distributed
12* on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
13* express or implied. See the License for the specific language governing
14* permissions and limitations under the License.
15*/
16
17#include <aws/core/utils/stream/SimpleStreamBuf.h>
18
19#include <algorithm>
20#include <cassert>
21#include <cstring>
22
23namespace Aws
24{
25namespace Utils
26{
27namespace Stream
28{
29
30static const uint32_t DEFAULT_BUFFER_SIZE = 100;
31static const char* SIMPLE_STREAMBUF_ALLOCATION_TAG = "SimpleStreamBufTag";
32
33SimpleStreamBuf::SimpleStreamBuf() :
34 m_buffer(nullptr),
35 m_bufferSize(0)
36{
37 m_buffer = Aws::NewArray<char>(DEFAULT_BUFFER_SIZE, SIMPLE_STREAMBUF_ALLOCATION_TAG);
38 m_bufferSize = DEFAULT_BUFFER_SIZE;
39
40 char* begin = m_buffer;
41 char* end = begin + m_bufferSize;
42
43 setp(begin, end);
44 setg(begin, begin, begin);
45}
46
47SimpleStreamBuf::SimpleStreamBuf(const Aws::String& value) :
48 m_buffer(nullptr),
49 m_bufferSize(0)
50{
51 size_t baseSize = (std::max)(value.size(), static_cast<std::size_t>(DEFAULT_BUFFER_SIZE));
52
53 m_buffer = Aws::NewArray<char>(baseSize, SIMPLE_STREAMBUF_ALLOCATION_TAG);
54 m_bufferSize = baseSize;
55
56 std::memcpy(m_buffer, value.c_str(), value.size());
57
58 char* begin = m_buffer;
59 char* end = begin + m_bufferSize;
60
61 setp(begin + value.size(), end);
62 setg(begin, begin, begin);
63}
64
65SimpleStreamBuf::~SimpleStreamBuf()
66{
67 if(m_buffer)
68 {
69 Aws::DeleteArray<char>(m_buffer);
70 m_buffer = nullptr;
71 }
72
73 m_bufferSize = 0;
74}
75
76std::streampos SimpleStreamBuf::seekoff(std::streamoff off, std::ios_base::seekdir dir, std::ios_base::openmode which)
77{
78 if (dir == std::ios_base::beg)
79 {
80 return seekpos(off, which);
81 }
82 else if (dir == std::ios_base::end)
83 {
84 return seekpos((pptr() - m_buffer) - off, which);
85 }
86 else if (dir == std::ios_base::cur)
87 {
88 if(which == std::ios_base::in)
89 {
90 return seekpos((gptr() - m_buffer) + off, which);
91 }
92 else
93 {
94 return seekpos((pptr() - m_buffer) + off, which);
95 }
96 }
97
98 return off_type(-1);
99}
100
101std::streampos SimpleStreamBuf::seekpos(std::streampos pos, std::ios_base::openmode which)
102{
103 size_t maxSeek = pptr() - m_buffer;
104 assert(static_cast<size_t>(pos) <= maxSeek);
105 if (static_cast<size_t>(pos) > maxSeek)
106 {
107 return pos_type(off_type(-1));
108 }
109
110 if (which == std::ios_base::in)
111 {
112 setg(m_buffer, m_buffer + static_cast<size_t>(pos), pptr());
113 }
114
115 if (which == std::ios_base::out)
116 {
117 setp(m_buffer + static_cast<size_t>(pos), epptr());
118 }
119
120 return pos;
121}
122
123bool SimpleStreamBuf::GrowBuffer()
124{
125 size_t currentSize = m_bufferSize;
126 size_t newSize = currentSize * 2;
127
128 char* newBuffer = Aws::NewArray<char>(newSize, SIMPLE_STREAMBUF_ALLOCATION_TAG);
129 if(newBuffer == nullptr)
130 {
131 return false;
132 }
133
134 if(currentSize > 0)
135 {
136 std::memcpy(newBuffer, m_buffer, currentSize);
137 }
138
139 if(m_buffer)
140 {
141 Aws::DeleteArray<char>(m_buffer);
142 }
143
144 m_buffer = newBuffer;
145 m_bufferSize = newSize;
146
147 return true;
148}
149
150int SimpleStreamBuf::overflow (int c)
151{
152 auto endOfFile = std::char_traits< char >::eof();
153 if(c == endOfFile)
154 {
155 return endOfFile;
156 }
157
158 char* old_begin = m_buffer;
159
160 char *old_pptr = pptr();
161 char *old_gptr = gptr();
162 char *old_egptr = egptr();
163
164 size_t currentWritePosition = m_bufferSize;
165
166 if(!GrowBuffer())
167 {
168 return endOfFile;
169 }
170
171 char* new_begin = m_buffer;
172 char* new_end = new_begin + m_bufferSize;
173
174 setp(new_begin + (old_pptr - old_begin) + 1, new_end);
175 setg(new_begin, new_begin + (old_gptr - old_begin), new_begin + (old_egptr - old_begin));
176
177 auto val = std::char_traits< char >::to_char_type(c);
178 *(new_begin + currentWritePosition) = val;
179
180 return c;
181}
182
183std::streamsize SimpleStreamBuf::xsputn(const char* s, std::streamsize n)
184{
185 std::streamsize writeCount = 0;
186 while(writeCount < n)
187 {
188 char* current_pptr = pptr();
189 char* current_epptr = epptr();
190
191 if (current_pptr < current_epptr)
192 {
193 std::size_t copySize = (std::min)(static_cast< std::size_t >(n - writeCount),
194 static_cast< std::size_t >(current_epptr - current_pptr));
195
196 std::memcpy(current_pptr, s + writeCount, copySize);
197 writeCount += copySize;
198 setp(current_pptr + copySize, current_epptr);
199 setg(m_buffer, gptr(), pptr());
200 }
201 else if (overflow(std::char_traits< char >::to_int_type(*(s + writeCount))) != std::char_traits<char>::eof())
202 {
203 writeCount++;
204 }
205 else
206 {
207 return writeCount;
208 }
209 }
210
211 return writeCount;
212}
213
214Aws::String SimpleStreamBuf::str() const
215{
216 return Aws::String(m_buffer, pptr());
217}
218
219int SimpleStreamBuf::underflow()
220{
221 if(egptr() != pptr())
222 {
223 setg(m_buffer, gptr(), pptr());
224 }
225
226 if(gptr() != egptr())
227 {
228 return std::char_traits< char >::to_int_type(*gptr());
229 }
230 else
231 {
232 return std::char_traits< char >::eof();
233 }
234}
235
236void SimpleStreamBuf::str(const Aws::String& value)
237{
238 char* begin = m_buffer;
239 char* end = begin + m_bufferSize;
240
241 setp(begin, end);
242 setg(begin, begin, begin);
243
244 xsputn(value.c_str(), value.size());
245}
246
247}
248}
249}
250