LCOV - code coverage report
Current view: top level - src/tds - read.c (source / functions) Hit Total Coverage
Test: FreeTDS coverage Lines: 65 69 94.2 %
Date: 2024-04-18 20:40:06 Functions: 11 11 100.0 %

          Line data    Source code
       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/utils/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
      72     1184614 : tds_get_byte(TDSSOCKET * tds)
      73             : {
      74     2432849 :         while (tds->in_pos >= tds->in_len) {
      75       63659 :                 if (tds_read_packet(tds) < 0)
      76             :                         return 0;
      77             :         }
      78     1184576 :         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
      89       49804 : tds_unget_byte(TDSSOCKET * tds)
      90             : {
      91             :         /* this is a one trick pony...don't call it twice */
      92       49804 :         tds->in_pos--;
      93       49804 : }
      94             : 
      95             : /**
      96             :  * Reads a byte from the TDS stream without removing it
      97             :  * \tds
      98             :  */
      99             : unsigned char
     100       28953 : tds_peek(TDSSOCKET * tds)
     101             : {
     102       28953 :         unsigned char result = tds_get_byte(tds);
     103       28953 :         if (tds->in_pos > 0)
     104       28953 :                 --tds->in_pos;
     105       28953 :         return result;
     106             : }                               /* tds_peek()  */
     107             : 
     108             : 
     109             : /**
     110             :  * Get an int16 from the server.
     111             :  */
     112             : TDS_USMALLINT
     113      753930 : tds_get_usmallint(TDSSOCKET * tds)
     114             : {
     115             :         TDS_USMALLINT bytes[1];
     116             : 
     117      753930 :         tds_get_n(tds, &bytes, 2);
     118      753930 :         return (TDS_USMALLINT) TDS_GET_A2LE(&bytes);
     119             : }
     120             : 
     121             : 
     122             : /**
     123             :  * Get an int32 from the server.
     124             :  * \tds
     125             :  */
     126             : TDS_UINT
     127      197873 : tds_get_uint(TDSSOCKET * tds)
     128             : {
     129             :         TDS_UINT bytes;
     130             : 
     131      197873 :         tds_get_n(tds, &bytes, 4);
     132      197873 :         return TDS_GET_A4LE(&bytes);
     133             : }
     134             : 
     135             : /**
     136             :  * Get an uint64 from the server.
     137             :  * \tds
     138             :  */
     139             : TDS_UINT8
     140       32977 : tds_get_uint8(TDSSOCKET * tds)
     141             : {
     142             :         TDS_UINT h;
     143             :         TDS_UINT l;
     144             :         TDS_UINT bytes[2];
     145             : 
     146       32977 :         tds_get_n(tds, bytes, 8);
     147       32977 :         l = TDS_GET_A4LE(bytes);
     148       32977 :         h = TDS_GET_A4LE(bytes+1);
     149       32977 :         return (((TDS_UINT8) h) << 32) | l;
     150             : }
     151             : 
     152             : /**
     153             :  * Fetch a string from the wire.
     154             :  * Output string is NOT null terminated.
     155             :  * If TDS version is 7 or 8 read unicode string and convert it.
     156             :  * This function should be use to read server default encoding strings like 
     157             :  * columns name, table names, etc, not for data (use tds_get_char_data instead)
     158             :  * @return bytes written to \a dest
     159             :  * @param tds  connection information
     160             :  * @param string_len length of string to read from wire 
     161             :  *        (in server characters, bytes for tds4-tds5, ucs2 for tds7+)
     162             :  * @param dest destination buffer, if NULL string is read and discarded
     163             :  * @param dest_size destination buffer size, in bytes
     164             :  */
     165             : size_t
     166      146083 : tds_get_string(TDSSOCKET * tds, size_t string_len, char *dest, size_t dest_size)
     167             : {
     168      146083 :         size_t wire_bytes = string_len;
     169      146083 :         unsigned conv = client2server_chardata;
     170             : 
     171      146083 :         if (IS_TDS7_PLUS(tds->conn)) {
     172       95766 :                 wire_bytes *= 2u;
     173       95766 :                 conv = client2ucs2;
     174             :         }
     175             : 
     176      146083 :         if (dest == NULL) {
     177          22 :                 tds_get_n(tds, NULL, wire_bytes);
     178          22 :                 return string_len;
     179             :         }
     180             : 
     181      146061 :         return read_and_convert(tds, tds->conn->char_convs[conv], &wire_bytes, dest, dest_size);
     182             : }
     183             : 
     184             : /**
     185             :  * Fetch character data the wire.
     186             :  * Output is NOT null terminated.
     187             :  * If \a char_conv is not NULL, convert data accordingly.
     188             :  * \param tds         state information for the socket and the TDS protocol
     189             :  * \param row_buffer  destination buffer in current_row. Can't be NULL
     190             :  * \param wire_size   size to read from wire (in bytes)
     191             :  * \param curcol      column information
     192             :  * \return TDS_SUCCESS or TDS_FAIL (probably memory error on text data)
     193             :  */
     194             : TDSRET
     195      370446 : tds_get_char_data(TDSSOCKET * tds, char *row_buffer, size_t wire_size, TDSCOLUMN * curcol)
     196             : {
     197             :         size_t in_left;
     198             : 
     199      370446 :         assert(curcol->char_conv);
     200             : 
     201             :         /*
     202             :          * row_buffer is a column buffer, allocated when the column's metadata are processed
     203             :          * and reused for each row.
     204             :          */
     205             : 
     206             :         /* silly case, empty string */
     207      370446 :         if (wire_size == 0) {
     208          66 :                 curcol->column_cur_size = 0;
     209          66 :                 return TDS_SUCCESS;
     210             :         }
     211             : 
     212      370380 :         in_left = curcol->column_size;
     213      370380 :         curcol->column_cur_size = read_and_convert(tds, curcol->char_conv, &wire_size, row_buffer, in_left);
     214      370380 :         if (TDS_UNLIKELY(wire_size > 0)) {
     215           0 :                 tds_get_n(tds, NULL, wire_size);
     216           0 :                 tdsdump_log(TDS_DBG_NETWORK, "error: tds_get_char_data: discarded %u on wire while reading %d into client. \n",
     217             :                                                  (unsigned int) wire_size, curcol->column_cur_size);
     218             :                 return TDS_FAIL;
     219             :         }
     220             :         return TDS_SUCCESS;
     221             : }
     222             : 
     223             : /**
     224             :  * Get N bytes from the buffer and return them in the already allocated space  
     225             :  * given to us.  We ASSUME that the person calling this function has done the  
     226             :  * bounds checking for us since they know how many bytes they want here.
     227             :  * dest of NULL means we just want to eat the bytes.   (tetherow@nol.org)
     228             :  */
     229             : bool
     230     2313012 : tds_get_n(TDSSOCKET * tds, void *dest, size_t need)
     231             : {
     232             :         for (;;) {
     233     2318356 :                 unsigned int have = tds->in_len - tds->in_pos;
     234             : 
     235     2318356 :                 if (need <= have)
     236             :                         break;
     237             :                 /* We need more than is in the buffer, copy what is there */
     238        5344 :                 if (dest != NULL) {
     239        5343 :                         memcpy((char *) dest, tds->in_buf + tds->in_pos, have);
     240        5343 :                         dest = (char *) dest + have;
     241             :                 }
     242        5344 :                 need -= have;
     243        5344 :                 if (TDS_UNLIKELY(tds_read_packet(tds) < 0))
     244             :                         return false;
     245             :         }
     246     2313012 :         if (need > 0) {
     247             :                 /* get the remainder if there is any */
     248     1972363 :                 if (dest != NULL) {
     249     1937163 :                         memcpy((char *) dest, tds->in_buf + tds->in_pos, need);
     250             :                 }
     251     1972363 :                 tds->in_pos += need;
     252             :         }
     253             :         return true;
     254             : }
     255             : 
     256             : /**
     257             :  * For UTF-8 and similar, tds_iconv() may encounter a partial sequence when the chunk boundary
     258             :  * is not aligned with the character boundary.  In that event, it will return an error, and
     259             :  * some number of bytes (less than a character) will remain in the tail end of temp[].  They are
     260             :  * moved to the beginning, ptemp is adjusted to point just behind them, and the next chunk is read.
     261             :  * \tds
     262             :  * \param char_conv conversion structure
     263             :  * \param[out] wire_size size readed from wire
     264             :  * \param outbuf buffer to write to
     265             :  * \param outbytesleft buffer length
     266             :  * \return bytes readed
     267             :  */
     268             : static size_t
     269      516441 : read_and_convert(TDSSOCKET * tds, TDSICONV * char_conv, size_t * wire_size, char *outbuf,
     270             :                  size_t outbytesleft)
     271             : {
     272             :         int res;
     273             :         TDSDATAINSTREAM r;
     274             :         TDSSTATICOUTSTREAM w;
     275             : 
     276      516441 :         tds_datain_stream_init(&r, tds, *wire_size);
     277      516441 :         tds_staticout_stream_init(&w, outbuf, outbytesleft);
     278             : 
     279      516441 :         res = tds_convert_stream(tds, char_conv, to_client, &r.stream, &w.stream);
     280      516441 :         *wire_size = r.wire_size;
     281      516441 :         return (char *) w.stream.buffer - outbuf;
     282             : }
     283             : 
     284             : /**
     285             :  * Reads a string from wire and put in a DSTR.
     286             :  * On error we read the bytes from the wire anyway.
     287             :  * \tds
     288             :  * \param[out] s output string
     289             :  * \param[in] len string length (in characters)
     290             :  * \return string or NULL on error
     291             :  */
     292             : DSTR*
     293       83660 : tds_dstr_get(TDSSOCKET * tds, DSTR * s, size_t len)
     294             : {
     295             :         size_t out_len;
     296             : 
     297       83660 :         CHECK_TDS_EXTRA(tds);
     298             : 
     299             :         /* assure sufficient space for every conversion */
     300       83660 :         if (TDS_UNLIKELY(!tds_dstr_alloc(s, len * 4))) {
     301           0 :                 tds_get_n(tds, NULL, len);
     302           0 :                 return NULL;
     303             :         }
     304             : 
     305      167320 :         out_len = tds_get_string(tds, len, tds_dstr_buf(s), len * 4);
     306       83660 :         tds_dstr_setlen(s, out_len);
     307       83660 :         return s;
     308             : }
     309             : 
     310             : /** @} */

Generated by: LCOV version 1.13