wpabuf.c revision 526fc2a7dc09b4450086cdec313a5c44d36b10fd
1526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt/*
2526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt * Dynamic data buffer
3526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt * Copyright (c) 2007-2009, Jouni Malinen <j@w1.fi>
4526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt *
5526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt * This program is free software; you can redistribute it and/or modify
6526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt * it under the terms of the GNU General Public License version 2 as
7526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt * published by the Free Software Foundation.
8526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt *
9526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt * Alternatively, this software may be distributed under the terms of BSD
10526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt * license.
11526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt *
12526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt * See README and COPYING for more details.
13526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt */
14526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
15526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt#include "includes.h"
16526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
17526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt#include "common.h"
18526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt#include "wpabuf.h"
19526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
20526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidtstatic void wpabuf_overflow(const struct wpabuf *buf, size_t len)
21526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt{
22526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	wpa_printf(MSG_ERROR, "wpabuf %p (size=%lu used=%lu) overflow len=%lu",
23526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		   buf, (unsigned long) buf->size, (unsigned long) buf->used,
24526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		   (unsigned long) len);
25526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	abort();
26526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt}
27526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
28526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
29526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidtint wpabuf_resize(struct wpabuf **_buf, size_t add_len)
30526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt{
31526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	struct wpabuf *buf = *_buf;
32526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	if (buf->used + add_len > buf->size) {
33526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		unsigned char *nbuf;
34526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		if (buf->ext_data) {
35526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt			nbuf = os_realloc(buf->ext_data, buf->used + add_len);
36526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt			if (nbuf == NULL)
37526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt				return -1;
38526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt			os_memset(nbuf + buf->used, 0, add_len);
39526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt			buf->ext_data = nbuf;
40526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		} else {
41526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt			nbuf = os_realloc(buf, sizeof(struct wpabuf) +
42526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt					  buf->used + add_len);
43526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt			if (nbuf == NULL)
44526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt				return -1;
45526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt			buf = (struct wpabuf *) nbuf;
46526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt			os_memset(nbuf + sizeof(struct wpabuf) + buf->used, 0,
47526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt				  add_len);
48526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt			*_buf = buf;
49526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		}
50526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		buf->size = buf->used + add_len;
51526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	}
52526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
53526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	return 0;
54526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt}
55526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
56526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
57526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt/**
58526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt * wpabuf_alloc - Allocate a wpabuf of the given size
59526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt * @len: Length for the allocated buffer
60526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt * Returns: Buffer to the allocated wpabuf or %NULL on failure
61526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt */
62526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidtstruct wpabuf * wpabuf_alloc(size_t len)
63526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt{
64526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	struct wpabuf *buf = os_zalloc(sizeof(struct wpabuf) + len);
65526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	if (buf == NULL)
66526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		return NULL;
67526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	buf->size = len;
68526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	return buf;
69526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt}
70526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
71526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
72526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidtstruct wpabuf * wpabuf_alloc_ext_data(u8 *data, size_t len)
73526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt{
74526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	struct wpabuf *buf = os_zalloc(sizeof(struct wpabuf));
75526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	if (buf == NULL)
76526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		return NULL;
77526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
78526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	buf->size = len;
79526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	buf->used = len;
80526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	buf->ext_data = data;
81526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
82526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	return buf;
83526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt}
84526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
85526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
86526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidtstruct wpabuf * wpabuf_alloc_copy(const void *data, size_t len)
87526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt{
88526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	struct wpabuf *buf = wpabuf_alloc(len);
89526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	if (buf)
90526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		wpabuf_put_data(buf, data, len);
91526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	return buf;
92526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt}
93526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
94526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
95526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidtstruct wpabuf * wpabuf_dup(const struct wpabuf *src)
96526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt{
97526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	struct wpabuf *buf = wpabuf_alloc(wpabuf_len(src));
98526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	if (buf)
99526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		wpabuf_put_data(buf, wpabuf_head(src), wpabuf_len(src));
100526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	return buf;
101526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt}
102526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
103526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
104526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt/**
105526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt * wpabuf_free - Free a wpabuf
106526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt * @buf: wpabuf buffer
107526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt */
108526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidtvoid wpabuf_free(struct wpabuf *buf)
109526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt{
110526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	if (buf == NULL)
111526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		return;
112526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	os_free(buf->ext_data);
113526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	os_free(buf);
114526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt}
115526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
116526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
117526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidtvoid * wpabuf_put(struct wpabuf *buf, size_t len)
118526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt{
119526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	void *tmp = wpabuf_mhead_u8(buf) + wpabuf_len(buf);
120526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	buf->used += len;
121526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	if (buf->used > buf->size) {
122526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		wpabuf_overflow(buf, len);
123526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	}
124526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	return tmp;
125526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt}
126526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
127526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
128526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt/**
129526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt * wpabuf_concat - Concatenate two buffers into a newly allocated one
130526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt * @a: First buffer
131526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt * @b: Second buffer
132526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt * Returns: wpabuf with concatenated a + b data or %NULL on failure
133526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt *
134526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt * Both buffers a and b will be freed regardless of the return value. Input
135526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt * buffers can be %NULL which is interpreted as an empty buffer.
136526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt */
137526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidtstruct wpabuf * wpabuf_concat(struct wpabuf *a, struct wpabuf *b)
138526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt{
139526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	struct wpabuf *n = NULL;
140526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	size_t len = 0;
141526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
142526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	if (b == NULL)
143526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		return a;
144526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
145526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	if (a)
146526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		len += wpabuf_len(a);
147526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	if (b)
148526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		len += wpabuf_len(b);
149526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
150526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	n = wpabuf_alloc(len);
151526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	if (n) {
152526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		if (a)
153526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt			wpabuf_put_buf(n, a);
154526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		if (b)
155526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt			wpabuf_put_buf(n, b);
156526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	}
157526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
158526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	wpabuf_free(a);
159526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	wpabuf_free(b);
160526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
161526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	return n;
162526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt}
163526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
164526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
165526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt/**
166526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt * wpabuf_zeropad - Pad buffer with 0x00 octets (prefix) to specified length
167526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt * @buf: Buffer to be padded
168526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt * @len: Length for the padded buffer
169526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt * Returns: wpabuf padded to len octets or %NULL on failure
170526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt *
171526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt * If buf is longer than len octets or of same size, it will be returned as-is.
172526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt * Otherwise a new buffer is allocated and prefixed with 0x00 octets followed
173526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt * by the source data. The source buffer will be freed on error, i.e., caller
174526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt * will only be responsible on freeing the returned buffer. If buf is %NULL,
175526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt * %NULL will be returned.
176526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt */
177526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidtstruct wpabuf * wpabuf_zeropad(struct wpabuf *buf, size_t len)
178526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt{
179526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	struct wpabuf *ret;
180526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	size_t blen;
181526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
182526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	if (buf == NULL)
183526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		return NULL;
184526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
185526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	blen = wpabuf_len(buf);
186526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	if (blen >= len)
187526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		return buf;
188526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
189526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	ret = wpabuf_alloc(len);
190526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	if (ret) {
191526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		os_memset(wpabuf_put(ret, len - blen), 0, len - blen);
192526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		wpabuf_put_buf(ret, buf);
193526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	}
194526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	wpabuf_free(buf);
195526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
196526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	return ret;
197526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt}
198526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
199526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
200526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidtvoid wpabuf_printf(struct wpabuf *buf, char *fmt, ...)
201526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt{
202526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	va_list ap;
203526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	void *tmp = wpabuf_mhead_u8(buf) + wpabuf_len(buf);
204526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	int res;
205526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
206526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	va_start(ap, fmt);
207526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	res = vsnprintf(tmp, buf->size - buf->used, fmt, ap);
208526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	va_end(ap);
209526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	if (res < 0 || (size_t) res >= buf->size - buf->used)
210526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		wpabuf_overflow(buf, res);
211526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	buf->used += res;
212526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt}
213