1/*
2 * Copyright (C) 2011 Google Inc. All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions are
6 * met:
7 *
8 *     * Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 *     * Redistributions in binary form must reproduce the above
11 * copyright notice, this list of conditions and the following disclaimer
12 * in the documentation and/or other materials provided with the
13 * distribution.
14 *     * Neither the name of Google Inc. nor the names of its
15 * contributors may be used to endorse or promote products derived from
16 * this software without specific prior written permission.
17 *
18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
21 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
22 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
23 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
24 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 */
30
31#include "config.h"
32#include "platform/SharedBufferChunkReader.h"
33
34#include "platform/SharedBuffer.h"
35
36namespace blink {
37
38SharedBufferChunkReader::SharedBufferChunkReader(SharedBuffer* buffer, const Vector<char>& separator)
39    : m_buffer(buffer)
40    , m_bufferPosition(0)
41    , m_segment(0)
42    , m_segmentLength(0)
43    , m_segmentIndex(0)
44    , m_reachedEndOfFile(false)
45    , m_separator(separator)
46    , m_separatorIndex(0)
47{
48}
49
50SharedBufferChunkReader::SharedBufferChunkReader(SharedBuffer* buffer, const char* separator)
51    : m_buffer(buffer)
52    , m_bufferPosition(0)
53    , m_segment(0)
54    , m_segmentLength(0)
55    , m_segmentIndex(0)
56    , m_reachedEndOfFile(false)
57    , m_separatorIndex(0)
58{
59    setSeparator(separator);
60}
61
62void SharedBufferChunkReader::setSeparator(const Vector<char>& separator)
63{
64    m_separator = separator;
65}
66
67void SharedBufferChunkReader::setSeparator(const char* separator)
68{
69    m_separator.clear();
70    m_separator.append(separator, strlen(separator));
71}
72
73bool SharedBufferChunkReader::nextChunk(Vector<char>& chunk, bool includeSeparator)
74{
75    if (m_reachedEndOfFile)
76        return false;
77
78    chunk.clear();
79    while (true) {
80        while (m_segmentIndex < m_segmentLength) {
81            char currentCharacter = m_segment[m_segmentIndex++];
82            if (currentCharacter != m_separator[m_separatorIndex]) {
83                if (m_separatorIndex > 0) {
84                    ASSERT_WITH_SECURITY_IMPLICATION(m_separatorIndex <= m_separator.size());
85                    chunk.append(m_separator.data(), m_separatorIndex);
86                    m_separatorIndex = 0;
87                }
88                chunk.append(currentCharacter);
89                continue;
90            }
91            m_separatorIndex++;
92            if (m_separatorIndex == m_separator.size()) {
93                if (includeSeparator)
94                    chunk.appendVector(m_separator);
95                m_separatorIndex = 0;
96                return true;
97            }
98        }
99
100        // Read the next segment.
101        m_segmentIndex = 0;
102        m_bufferPosition += m_segmentLength;
103        m_segmentLength = m_buffer->getSomeData(m_segment, m_bufferPosition);
104        if (!m_segmentLength) {
105            m_reachedEndOfFile = true;
106            if (m_separatorIndex > 0)
107                chunk.append(m_separator.data(), m_separatorIndex);
108            return !chunk.isEmpty();
109        }
110    }
111    ASSERT_NOT_REACHED();
112    return false;
113}
114
115String SharedBufferChunkReader::nextChunkAsUTF8StringWithLatin1Fallback(bool includeSeparator)
116{
117    Vector<char> data;
118    if (!nextChunk(data, includeSeparator))
119        return String();
120
121    return data.size() ? String::fromUTF8WithLatin1Fallback(data.data(), data.size()) : emptyString();
122}
123
124size_t SharedBufferChunkReader::peek(Vector<char>& data, size_t requestedSize)
125{
126    data.clear();
127    if (requestedSize <= m_segmentLength - m_segmentIndex) {
128        data.append(m_segment + m_segmentIndex, requestedSize);
129        return requestedSize;
130    }
131
132    size_t readBytesCount = m_segmentLength - m_segmentIndex;
133    data.append(m_segment + m_segmentIndex, readBytesCount);
134
135    size_t bufferPosition = m_bufferPosition + m_segmentLength;
136    const char* segment = 0;
137    while (size_t segmentLength = m_buffer->getSomeData(segment, bufferPosition)) {
138        if (requestedSize <= readBytesCount + segmentLength) {
139            data.append(segment, requestedSize - readBytesCount);
140            readBytesCount += (requestedSize - readBytesCount);
141            break;
142        }
143        data.append(segment, segmentLength);
144        readBytesCount += segmentLength;
145        bufferPosition += segmentLength;
146    }
147    return readBytesCount;
148}
149
150}
151