blob: 523c9d78a11b52b0133498c4bf4387867e460b55 [file] [log] [blame]
Elliott Hughes872d4ec2011-10-21 17:07:15 -07001/*
2 * Copyright (C) 2008 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16/*
17 * Implementation of an expandable byte buffer. Designed for serializing
18 * primitive values, e.g. JDWP replies.
19 */
20
21#include "jdwp/jdwp_bits.h"
22#include "jdwp/jdwp_expand_buf.h"
23#include "logging.h"
24
25#include <stdlib.h>
26#include <string.h>
27
28namespace art {
29
30namespace JDWP {
31
32/*
33 * Data structure used to track buffer use.
34 */
35struct ExpandBuf {
36 uint8_t* storage;
37 int curLen;
38 int maxLen;
39};
40
41#define kInitialStorage 64
42
43/*
44 * Allocate a JdwpBuf and some initial storage.
45 */
46ExpandBuf* expandBufAlloc() {
Elliott Hughesa21039c2012-06-21 12:09:25 -070047 ExpandBuf* newBuf = new ExpandBuf;
48 newBuf->storage = reinterpret_cast<uint8_t*>(malloc(kInitialStorage));
Elliott Hughes872d4ec2011-10-21 17:07:15 -070049 newBuf->curLen = 0;
50 newBuf->maxLen = kInitialStorage;
Elliott Hughes872d4ec2011-10-21 17:07:15 -070051 return newBuf;
52}
53
54/*
55 * Free a JdwpBuf and associated storage.
56 */
57void expandBufFree(ExpandBuf* pBuf) {
58 if (pBuf == NULL) {
59 return;
60 }
61
62 free(pBuf->storage);
Elliott Hughesa21039c2012-06-21 12:09:25 -070063 delete pBuf;
Elliott Hughes872d4ec2011-10-21 17:07:15 -070064}
65
66/*
67 * Get a pointer to the start of the buffer.
68 */
69uint8_t* expandBufGetBuffer(ExpandBuf* pBuf) {
70 return pBuf->storage;
71}
72
73/*
74 * Get the amount of data currently in the buffer.
75 */
76size_t expandBufGetLength(ExpandBuf* pBuf) {
77 return pBuf->curLen;
78}
79
Elliott Hughes872d4ec2011-10-21 17:07:15 -070080/*
81 * Ensure that the buffer has enough space to hold incoming data. If it
82 * doesn't, resize the buffer.
83 */
84static void ensureSpace(ExpandBuf* pBuf, int newCount) {
85 if (pBuf->curLen + newCount <= pBuf->maxLen) {
86 return;
87 }
88
89 while (pBuf->curLen + newCount > pBuf->maxLen) {
90 pBuf->maxLen *= 2;
91 }
92
Elliott Hughesa21039c2012-06-21 12:09:25 -070093 uint8_t* newPtr = reinterpret_cast<uint8_t*>(realloc(pBuf->storage, pBuf->maxLen));
Elliott Hughes872d4ec2011-10-21 17:07:15 -070094 if (newPtr == NULL) {
Elliott Hughes6c1c69e2012-04-23 16:12:51 -070095 LOG(FATAL) << "realloc(" << pBuf->maxLen << ") failed";
Elliott Hughes872d4ec2011-10-21 17:07:15 -070096 }
97
98 pBuf->storage = newPtr;
99}
100
101/*
102 * Allocate some space in the buffer.
103 */
104uint8_t* expandBufAddSpace(ExpandBuf* pBuf, int gapSize) {
105 uint8_t* gapStart;
106
107 ensureSpace(pBuf, gapSize);
108 gapStart = pBuf->storage + pBuf->curLen;
109 /* do we want to garbage-fill the gap for debugging? */
110 pBuf->curLen += gapSize;
111
112 return gapStart;
113}
114
115/*
116 * Append a byte.
117 */
118void expandBufAdd1(ExpandBuf* pBuf, uint8_t val) {
119 ensureSpace(pBuf, sizeof(val));
120 *(pBuf->storage + pBuf->curLen) = val;
121 pBuf->curLen++;
122}
123
124/*
125 * Append two big-endian bytes.
126 */
127void expandBufAdd2BE(ExpandBuf* pBuf, uint16_t val) {
128 ensureSpace(pBuf, sizeof(val));
Elliott Hughesf7c3b662011-10-27 12:04:56 -0700129 Set2BE(pBuf->storage + pBuf->curLen, val);
Elliott Hughes872d4ec2011-10-21 17:07:15 -0700130 pBuf->curLen += sizeof(val);
131}
132
133/*
134 * Append four big-endian bytes.
135 */
136void expandBufAdd4BE(ExpandBuf* pBuf, uint32_t val) {
137 ensureSpace(pBuf, sizeof(val));
Elliott Hughesf7c3b662011-10-27 12:04:56 -0700138 Set4BE(pBuf->storage + pBuf->curLen, val);
Elliott Hughes872d4ec2011-10-21 17:07:15 -0700139 pBuf->curLen += sizeof(val);
140}
141
142/*
143 * Append eight big-endian bytes.
144 */
145void expandBufAdd8BE(ExpandBuf* pBuf, uint64_t val) {
146 ensureSpace(pBuf, sizeof(val));
Elliott Hughesf7c3b662011-10-27 12:04:56 -0700147 Set8BE(pBuf->storage + pBuf->curLen, val);
Elliott Hughes872d4ec2011-10-21 17:07:15 -0700148 pBuf->curLen += sizeof(val);
149}
150
Elliott Hughesa2155262011-11-16 16:26:58 -0800151static void SetUtf8String(uint8_t* buf, const char* str, size_t strLen) {
Elliott Hughes21f32d72011-11-09 17:44:13 -0800152 Set4BE(buf, strLen);
153 memcpy(buf + sizeof(uint32_t), str, strLen);
154}
155
Elliott Hughes872d4ec2011-10-21 17:07:15 -0700156/*
157 * Add a UTF8 string as a 4-byte length followed by a non-NULL-terminated
158 * string.
159 *
160 * Because these strings are coming out of the VM, it's safe to assume that
161 * they can be null-terminated (either they don't have null bytes or they
162 * have stored null bytes in a multi-byte encoding).
163 */
Elliott Hughes4740cdf2011-12-07 14:07:12 -0800164void expandBufAddUtf8String(ExpandBuf* pBuf, const char* s) {
165 int strLen = strlen(s);
Elliott Hughes872d4ec2011-10-21 17:07:15 -0700166 ensureSpace(pBuf, sizeof(uint32_t) + strLen);
Elliott Hughes4740cdf2011-12-07 14:07:12 -0800167 SetUtf8String(pBuf->storage + pBuf->curLen, s, strLen);
Elliott Hughes872d4ec2011-10-21 17:07:15 -0700168 pBuf->curLen += sizeof(uint32_t) + strLen;
169}
170
Elliott Hughes4740cdf2011-12-07 14:07:12 -0800171void expandBufAddUtf8String(ExpandBuf* pBuf, const std::string& s) {
172 ensureSpace(pBuf, sizeof(uint32_t) + s.size());
173 SetUtf8String(pBuf->storage + pBuf->curLen, s.data(), s.size());
174 pBuf->curLen += sizeof(uint32_t) + s.size();
175}
176
Elliott Hughes872d4ec2011-10-21 17:07:15 -0700177} // namespace JDWP
178
179} // namespace art