1/*
2 * Copyright (C) 2010, 2011 Apple 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
6 * are met:
7 * 1. Redistributions of source code must retain the above copyright
8 *    notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright
10 *    notice, this list of conditions and the following disclaimer in the
11 *    documentation and/or other materials provided with the distribution.
12 *
13 * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
14 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
15 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
17 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
18 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
19 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
20 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
21 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
22 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
23 * THE POSSIBILITY OF SUCH DAMAGE.
24 */
25
26#include "config.h"
27#include "ArgumentDecoder.h"
28
29#include "DataReference.h"
30#include <stdio.h>
31
32namespace CoreIPC {
33
34ArgumentDecoder::ArgumentDecoder(const uint8_t* buffer, size_t bufferSize)
35{
36    initialize(buffer, bufferSize);
37}
38
39ArgumentDecoder::ArgumentDecoder(const uint8_t* buffer, size_t bufferSize, Deque<Attachment>& attachments)
40{
41    initialize(buffer, bufferSize);
42
43    m_attachments.swap(attachments);
44}
45
46ArgumentDecoder::~ArgumentDecoder()
47{
48    ASSERT(m_buffer);
49    fastFree(m_buffer);
50#if !PLATFORM(QT) && !PLATFORM(GTK)
51    // FIXME: We need to dispose of the mach ports in cases of failure.
52#else
53    Deque<Attachment>::iterator end = m_attachments.end();
54    for (Deque<Attachment>::iterator it = m_attachments.begin(); it != end; ++it)
55        it->dispose();
56#endif
57}
58
59void ArgumentDecoder::initialize(const uint8_t* buffer, size_t bufferSize)
60{
61    m_buffer = static_cast<uint8_t*>(fastMalloc(bufferSize));
62    m_bufferPos = m_buffer;
63    m_bufferEnd = m_buffer + bufferSize;
64    memcpy(m_buffer, buffer, bufferSize);
65
66    // Decode the destination ID.
67    decodeUInt64(m_destinationID);
68}
69
70static inline uint8_t* roundUpToAlignment(uint8_t* ptr, unsigned alignment)
71{
72    ASSERT(alignment);
73    uintptr_t alignmentMask = alignment - 1;
74    return reinterpret_cast<uint8_t*>((reinterpret_cast<uintptr_t>(ptr) + alignmentMask) & ~alignmentMask);
75}
76
77bool ArgumentDecoder::alignBufferPosition(unsigned alignment, size_t size)
78{
79    uint8_t* buffer = roundUpToAlignment(m_bufferPos, alignment);
80    if (static_cast<size_t>(m_bufferEnd - buffer) < size) {
81        // We've walked off the end of this buffer.
82        markInvalid();
83        return false;
84    }
85
86    m_bufferPos = buffer;
87    return true;
88}
89
90bool ArgumentDecoder::bufferIsLargeEnoughToContain(unsigned alignment, size_t size) const
91{
92    return static_cast<size_t>(m_bufferEnd - roundUpToAlignment(m_bufferPos, alignment)) >= size;
93}
94
95bool ArgumentDecoder::decodeBytes(Vector<uint8_t>& buffer)
96{
97    uint64_t size;
98    if (!decodeUInt64(size))
99        return false;
100
101    if (!alignBufferPosition(1, size))
102        return false;
103
104    buffer.resize(size);
105    if (size > 0)
106        memcpy(&buffer[0], m_bufferPos, size);
107    m_bufferPos += size;
108    return true;
109}
110
111bool ArgumentDecoder::decodeBytes(DataReference& dataReference)
112{
113    uint64_t size;
114    if (!decodeUInt64(size))
115        return false;
116
117    if (!alignBufferPosition(1, size))
118        return false;
119
120    uint8_t* data = m_bufferPos;
121    m_bufferPos += size;
122
123    dataReference = DataReference(data, size);
124    return true;
125}
126
127bool ArgumentDecoder::decodeBytes(uint8_t* buffer, size_t bufferSize)
128{
129    // FIXME: Decoding the size is not strictly necessary here since we know the size upfront.
130    uint64_t size;
131    if (!decodeUInt64(size))
132        return false;
133
134    ASSERT(size == bufferSize);
135    if (size != bufferSize)
136        return false;
137
138    if (!alignBufferPosition(1, size))
139        return false;
140
141    memcpy(buffer, m_bufferPos, size);
142    m_bufferPos += size;
143    return true;
144}
145
146bool ArgumentDecoder::decodeBool(bool& result)
147{
148    if (!alignBufferPosition(sizeof(result), sizeof(result)))
149        return false;
150
151    result = *reinterpret_cast<bool*>(m_bufferPos);
152    m_bufferPos += sizeof(result);
153    return true;
154}
155
156bool ArgumentDecoder::decodeUInt32(uint32_t& result)
157{
158    if (!alignBufferPosition(sizeof(result), sizeof(result)))
159        return false;
160
161    result = *reinterpret_cast<uint32_t*>(m_bufferPos);
162    m_bufferPos += sizeof(result);
163    return true;
164}
165
166bool ArgumentDecoder::decodeUInt64(uint64_t& result)
167{
168    if (!alignBufferPosition(sizeof(result), sizeof(result)))
169        return false;
170
171    result = *reinterpret_cast<uint64_t*>(m_bufferPos);
172    m_bufferPos += sizeof(result);
173    return true;
174}
175
176bool ArgumentDecoder::decodeInt32(int32_t& result)
177{
178    if (!alignBufferPosition(sizeof(result), sizeof(result)))
179        return false;
180
181    result = *reinterpret_cast<uint32_t*>(m_bufferPos);
182    m_bufferPos += sizeof(result);
183    return true;
184}
185
186bool ArgumentDecoder::decodeInt64(int64_t& result)
187{
188    if (!alignBufferPosition(sizeof(result), sizeof(result)))
189        return false;
190
191    result = *reinterpret_cast<uint64_t*>(m_bufferPos);
192    m_bufferPos += sizeof(result);
193    return true;
194}
195
196bool ArgumentDecoder::decodeFloat(float& result)
197{
198    if (!alignBufferPosition(sizeof(result), sizeof(result)))
199        return false;
200
201    result = *reinterpret_cast<float*>(m_bufferPos);
202    m_bufferPos += sizeof(result);
203    return true;
204}
205
206bool ArgumentDecoder::decodeDouble(double& result)
207{
208    if (!alignBufferPosition(sizeof(result), sizeof(result)))
209        return false;
210
211    result = *reinterpret_cast<double*>(m_bufferPos);
212    m_bufferPos += sizeof(result);
213    return true;
214}
215
216bool ArgumentDecoder::removeAttachment(Attachment& attachment)
217{
218    if (m_attachments.isEmpty())
219        return false;
220
221    attachment = m_attachments.takeFirst();
222    return true;
223}
224
225#ifndef NDEBUG
226void ArgumentDecoder::debug()
227{
228    printf("ArgumentDecoder::debug()\n");
229    printf("Number of Attachments: %d\n", (int)m_attachments.size());
230    printf("Size of buffer: %d\n", (int)(m_bufferEnd - m_buffer));
231}
232#endif
233
234} // namespace CoreIPC
235