NCBI C++ ToolKit
read.c
Go to the documentation of this file.

Go to the SVN repository for this file.

1 /* FreeTDS - Library of routines accessing Sybase and Microsoft databases
2  * Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2004 Brian Bruns
3  * Copyright (C) 2005-2014 Frediano Ziglio
4  *
5  * This library is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU Library General Public
7  * License as published by the Free Software Foundation; either
8  * version 2 of the License, or (at your option) any later version.
9  *
10  * This library is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13  * Library General Public License for more details.
14  *
15  * You should have received a copy of the GNU Library General Public
16  * License along with this library; if not, write to the
17  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18  * Boston, MA 02111-1307, USA.
19  */
20 
21 /**
22  * \file
23  * \brief Grab data from TDS packets
24  */
25 
26 #include <config.h>
27 
28 #if HAVE_ERRNO_H
29 #include <errno.h>
30 #endif /* HAVE_ERRNO_H */
31 
32 #if HAVE_STDLIB_H
33 #include <stdlib.h>
34 #endif /* HAVE_STDLIB_H */
35 
36 #if HAVE_STRING_H
37 #include <string.h>
38 #endif /* HAVE_STRING_H */
39 
40 #if HAVE_UNISTD_H
41 #include <unistd.h>
42 #endif /* HAVE_UNISTD_H */
43 
44 #include <assert.h>
45 
46 #include <freetds/tds.h>
47 #include <freetds/iconv.h>
48 #include <freetds/bytes.h>
49 #include <freetds/stream.h>
50 #include <freetds/string.h>
51 #include <freetds/checks.h>
52 
53 static size_t read_and_convert(TDSSOCKET * tds, TDSICONV * char_conv,
54  size_t * wire_size, char *outbuf, size_t outbytesleft);
55 
56 /**
57  * \ingroup libtds
58  * \defgroup network Network functions
59  * Functions for reading or writing from network.
60  */
61 
62 /**
63  * \addtogroup network
64  * @{
65  */
66 
67 /**
68  * Return a single byte from the input buffer
69  * \tds
70  */
71 unsigned char
73 {
74  while (tds->in_pos >= tds->in_len) {
75  if (tds_read_packet(tds) < 0)
76  return 0;
77  }
78  return tds->in_buf[tds->in_pos++];
79 }
80 
81 /**
82  * Unget will always work as long as you don't call it twice in a row. It
83  * it may work if you call it multiple times as long as you don't backup
84  * over the beginning of network packet boundary which can occur anywhere in
85  * the token stream.
86  * \tds
87  */
88 void
90 {
91  /* this is a one trick pony...don't call it twice */
92  tds->in_pos--;
93 }
94 
95 /**
96  * Reads a byte from the TDS stream without removing it
97  * \tds
98  */
99 unsigned char
101 {
102  unsigned char result = tds_get_byte(tds);
103  if (tds->in_pos > 0)
104  --tds->in_pos;
105  return result;
106 } /* tds_peek() */
107 
108 
109 /**
110  * Get an int16 from the server.
111  */
114 {
115  TDS_USMALLINT bytes[1];
116 
117  tds_get_n(tds, &bytes, 2);
118 #if WORDS_BIGENDIAN
120  return (TDS_USMALLINT) TDS_GET_A2LE(&bytes);
121 #endif
122  return (TDS_USMALLINT) TDS_GET_A2(&bytes);
123 }
124 
125 
126 /**
127  * Get an int32 from the server.
128  * \tds
129  */
130 TDS_UINT
132 {
133  TDS_UINT bytes;
134 
135  tds_get_n(tds, &bytes, 4);
136 #if WORDS_BIGENDIAN
138  return TDS_GET_A4LE(&bytes);
139 #endif
140  return TDS_GET_A4(&bytes);
141 }
142 
143 /**
144  * Get an uint64 from the server.
145  * \tds
146  */
147 TDS_UINT8
149 {
150  TDS_UINT h;
151  TDS_UINT l;
152  TDS_UINT bytes[2];
153 
154  tds_get_n(tds, bytes, 8);
155 #if WORDS_BIGENDIAN
156  if (tds->conn->emul_little_endian) {
157  l = TDS_GET_A4LE(bytes);
158  h = TDS_GET_A4LE(bytes+1);
159  } else {
160  h = TDS_GET_A4(bytes);
161  l = TDS_GET_A4(bytes+1);
162  }
163 #else
164  l = TDS_GET_A4(bytes);
165  h = TDS_GET_A4(bytes+1);
166 #endif
167  return (((TDS_UINT8) h) << 32) | l;
168 }
169 
170 /**
171  * Fetch a string from the wire.
172  * Output string is NOT null terminated.
173  * If TDS version is 7 or 8 read unicode string and convert it.
174  * This function should be use to read server default encoding strings like
175  * columns name, table names, etc, not for data (use tds_get_char_data instead)
176  * @return bytes written to \a dest
177  * @param tds connection information
178  * @param string_len length of string to read from wire
179  * (in server characters, bytes for tds4-tds5, ucs2 for tds7+)
180  * @param dest destination buffer, if NULL string is read and discarded
181  * @param dest_size destination buffer size, in bytes
182  */
183 size_t
184 tds_get_string(TDSSOCKET * tds, size_t string_len, char *dest, size_t dest_size)
185 {
186  size_t wire_bytes = string_len;
187  unsigned conv = client2server_chardata;
188 
189  if (IS_TDS7_PLUS(tds->conn)) {
190  wire_bytes *= 2u;
191  conv = client2ucs2;
192  }
193 
194  if (dest == NULL) {
195  tds_get_n(tds, NULL, wire_bytes);
196  return string_len;
197  }
198 
199  return read_and_convert(tds, tds->conn->char_convs[conv], &wire_bytes, dest, dest_size);
200 }
201 
202 /**
203  * Fetch character data the wire.
204  * Output is NOT null terminated.
205  * If \a char_conv is not NULL, convert data accordingly.
206  * \param tds state information for the socket and the TDS protocol
207  * \param row_buffer destination buffer in current_row. Can't be NULL
208  * \param wire_size size to read from wire (in bytes)
209  * \param curcol column information
210  * \return TDS_SUCCESS or TDS_FAIL (probably memory error on text data)
211  */
212 TDSRET
213 tds_get_char_data(TDSSOCKET * tds, char *row_buffer, size_t wire_size, TDSCOLUMN * curcol)
214 {
215  size_t in_left;
216 
217  assert(curcol->char_conv);
218 
219  /*
220  * row_buffer is a column buffer, allocated when the column's metadata are processed
221  * and reused for each row.
222  */
223 
224  /* silly case, empty string */
225  if (wire_size == 0) {
226  curcol->column_cur_size = 0;
227  return TDS_SUCCESS;
228  }
229 
230  in_left = curcol->column_size;
231  curcol->column_cur_size
232  = (TDS_INT) read_and_convert(tds, curcol->char_conv, &wire_size,
233  row_buffer, in_left);
234  if (TDS_UNLIKELY(wire_size > 0)) {
235  tds_get_n(tds, NULL, wire_size);
236  tdsdump_log(TDS_DBG_NETWORK, "error: tds_get_char_data: discarded %u on wire while reading %d into client. \n",
237  (unsigned int) wire_size, curcol->column_cur_size);
238  return TDS_FAIL;
239  }
240  return TDS_SUCCESS;
241 }
242 
243 /**
244  * Get N bytes from the buffer and return them in the already allocated space
245  * given to us. We ASSUME that the person calling this function has done the
246  * bounds checking for us since they know how many bytes they want here.
247  * dest of NULL means we just want to eat the bytes. (tetherow@nol.org)
248  */
249 void *
250 tds_get_n(TDSSOCKET * tds, void *dest, size_t need)
251 {
252  for (;;) {
253  unsigned int have = tds->in_len - tds->in_pos;
254 
255  if (need <= have)
256  break;
257  /* We need more than is in the buffer, copy what is there */
258  if (dest != NULL) {
259  memcpy((char *) dest, tds->in_buf + tds->in_pos, have);
260  dest = (char *) dest + have;
261  }
262  need -= have;
264  || tds->in_buf[1] != 0
265  || tds_read_packet(tds) < 0)) {
266  tds_close_socket(tds); /* evidently out of sync */
267  return NULL;
268  }
269  }
270  if (need > 0) {
271  /* get the remainder if there is any */
272  if (dest != NULL) {
273  memcpy((char *) dest, tds->in_buf + tds->in_pos, need);
274  }
275  tds->in_pos += (unsigned int) need;
276  }
277  return dest;
278 }
279 
280 /**
281  * For UTF-8 and similar, tds_iconv() may encounter a partial sequence when the chunk boundary
282  * is not aligned with the character boundary. In that event, it will return an error, and
283  * some number of bytes (less than a character) will remain in the tail end of temp[]. They are
284  * moved to the beginning, ptemp is adjusted to point just behind them, and the next chunk is read.
285  * \tds
286  * \param char_conv conversion structure
287  * \param[out] wire_size size readed from wire
288  * \param outbuf buffer to write to
289  * \param outbytesleft buffer length
290  * \return bytes readed
291  */
292 static size_t
293 read_and_convert(TDSSOCKET * tds, TDSICONV * char_conv, size_t * wire_size, char *outbuf,
294  size_t outbytesleft)
295 {
296  /* int res; */
299 
300  tds_datain_stream_init(&r, tds, *wire_size);
301  tds_staticout_stream_init(&w, outbuf, outbytesleft);
302 
303  /* res = */ tds_convert_stream(tds, char_conv, to_client,
304  &r.stream, &w.stream);
305  *wire_size = r.wire_size;
306  return (char *) w.stream.buffer - outbuf;
307 }
308 
309 /**
310  * Reads a string from wire and put in a DSTR.
311  * On error we read the bytes from the wire anyway.
312  * \tds
313  * \param[out] s output string
314  * \param[in] len string length (in characters)
315  * \return string or NULL on error
316  */
317 DSTR*
319 {
320  size_t out_len;
321 
323 
324  /* assure sufficient space for every conversion */
325  if (TDS_UNLIKELY(!tds_dstr_alloc(s, len * 4))) {
326  tds_get_n(tds, NULL, len);
327  return NULL;
328  }
329 
330  out_len = tds_get_string(tds, len, tds_dstr_buf(s), len * 4);
331  tds_dstr_setlen(s, out_len);
332  return s;
333 }
334 
335 /** @} */
#define TDS_GET_A2(ptr)
Definition: bytes.h:134
#define TDS_GET_A2LE(ptr)
Definition: bytes.h:140
#define TDS_GET_A4LE(ptr)
Definition: bytes.h:141
#define TDS_GET_A4(ptr)
Definition: bytes.h:136
#define CHECK_TDS_EXTRA(tds)
Definition: checks.h:31
@ to_client
Definition: iconv.h:70
#define TDS_FAIL
Definition: tds.h:204
tds_sysdep_int32_type TDS_INT
Definition: tds.h:149
@ client2server_chardata
Definition: tds.h:1110
@ client2ucs2
Definition: tds.h:1109
#define tdsdump_log
Definition: tds.h:1561
#define IS_TDS7_PLUS(x)
Definition: tds.h:1708
tds_sysdep_uint64_type TDS_UINT8
Definition: tds.h:154
int TDSRET
Definition: tds.h:201
tds_sysdep_uint16_type TDS_USMALLINT
Definition: tds.h:148
#define TDS_UNLIKELY(x)
Definition: tds.h:372
#define TDS_SUCCESS
Definition: tds.h:203
tds_sysdep_uint32_type TDS_UINT
Definition: tds.h:150
#define TDS_DBG_NETWORK
Definition: tds.h:901
static TDSICONV * conv
Definition: charconv.c:168
static TDSSOCKET * tds
Definition: collations.c:37
#define tds_convert_stream
#define tds_close_socket
#define tds_read_packet
#define tds_datain_stream_init
#define tds_staticout_stream_init
#define NULL
Definition: ncbistd.hpp:225
DSTR * tds_dstr_setlen(DSTR *s, size_t length)
limit length of string, MUST be <= current length
Definition: tdsstring.c:146
DSTR * tds_dstr_alloc(DSTR *s, size_t length) TDS_WUR
allocate space for length char
Definition: tdsstring.c:166
static char * tds_dstr_buf(DSTR *s)
Returns a buffer to edit the string.
Definition: string.h:59
unsigned int
A callback function used to compare two keys in a database.
Definition: types.hpp:1210
unsigned char tds_get_byte(TDSSOCKET *tds)
Return a single byte from the input buffer \tds.
Definition: read.c:72
unsigned char tds_peek(TDSSOCKET *tds)
Reads a byte from the TDS stream without removing it \tds.
Definition: read.c:100
static size_t read_and_convert(TDSSOCKET *tds, TDSICONV *char_conv, size_t *wire_size, char *outbuf, size_t outbytesleft)
For UTF-8 and similar, tds_iconv() may encounter a partial sequence when the chunk boundary is not al...
Definition: read.c:293
TDS_UINT8 tds_get_uint8(TDSSOCKET *tds)
Get an uint64 from the server.
Definition: read.c:148
TDSRET tds_get_char_data(TDSSOCKET *tds, char *row_buffer, size_t wire_size, TDSCOLUMN *curcol)
Fetch character data the wire.
Definition: read.c:213
size_t tds_get_string(TDSSOCKET *tds, size_t string_len, char *dest, size_t dest_size)
Fetch a string from the wire.
Definition: read.c:184
TDS_UINT tds_get_uint(TDSSOCKET *tds)
Get an int32 from the server.
Definition: read.c:131
TDS_USMALLINT tds_get_usmallint(TDSSOCKET *tds)
Get an int16 from the server.
Definition: read.c:113
void tds_unget_byte(TDSSOCKET *tds)
Unget will always work as long as you don't call it twice in a row.
Definition: read.c:89
void * tds_get_n(TDSSOCKET *tds, void *dest, size_t need)
Get N bytes from the buffer and return them in the already allocated space given to us.
Definition: read.c:250
DSTR * tds_dstr_get(TDSSOCKET *tds, DSTR *s, size_t len)
Reads a string from wire and put in a DSTR.
Definition: read.c:318
int len
double r(size_t dimension_, const Int4 *score_, const double *prob_, double theta_)
#define assert(x)
Definition: srv_diag.hpp:58
Metadata about columns in regular and compute rows.
Definition: tds.h:761
TDS_INT column_size
maximun size of data.
Definition: tds.h:766
TDSICONV * char_conv
refers to previously allocated iconv information
Definition: tds.h:784
TDS_INT column_cur_size
size written in variable (ie: char, text, binary).
Definition: tds.h:811
TDSICONV ** char_convs
Definition: tds.h:1161
unsigned int emul_little_endian
Definition: tds.h:1167
input stream to read data from tds protocol
Definition: stream.h:63
Structure to hold a string.
Definition: tds.h:116
char * buffer
write buffer.
Definition: stream.h:50
unsigned capacity
Definition: tds.h:1126
Information for a server connection.
Definition: tds.h:1211
unsigned in_len
input buffer length
Definition: tds.h:1239
unsigned char * in_buf
Input buffer.
Definition: tds.h:1223
unsigned in_pos
current position in in_buf
Definition: tds.h:1237
TDSCONNECTION conn[1]
Definition: tds.h:1215
TDSPACKET * recv_packet
Definition: tds.h:1254
output stream to write data to a static buffer.
Definition: stream.h:92
TDSOUTSTREAM stream
Definition: stream.h:93
else result
Definition: token2.c:20
uchar outbuf[(1000000+1000000)]
Definition: unzcrash.c:41
Modified on Sat Jun 15 11:53:46 2024 by modify_doxy.py rev. 669887