/** * Fetch character data the wire. * Output is NOT null terminated. * If \a char_conv is not NULL, convert data accordingly. * \param tds state information for the socket and the TDS protocol * \param row_buffer destination buffer in current_row. Can't be NULL * \param wire_size size to read from wire (in bytes) * \param curcol column information * \return TDS_SUCCESS or TDS_FAIL (probably memory error on text data) */ TDSRET tds_get_char_data(TDSSOCKET * tds, char *row_buffer, size_t wire_size, TDSCOLUMN * curcol) { size_t in_left; assert(curcol->char_conv); /* * row_buffer is a column buffer, allocated when the column's metadata are processed * and reused for each row. */ /* silly case, empty string */ if (wire_size == 0) { curcol->column_cur_size = 0; return TDS_SUCCESS; } in_left = curcol->column_size; curcol->column_cur_size = read_and_convert(tds, curcol->char_conv, &wire_size, row_buffer, in_left); if (TDS_UNLIKELY(wire_size > 0)) { tds_get_n(tds, NULL, wire_size); tdsdump_log(TDS_DBG_NETWORK, "error: tds_get_char_data: discarded %u on wire while reading %d into client. \n", (unsigned int) wire_size, curcol->column_cur_size); return TDS_FAIL; } return TDS_SUCCESS; }
/** * Fetch a string from the wire. * Output string is NOT null terminated. * If TDS version is 7 or 8 read unicode string and convert it. * This function should be use to read server default encoding strings like * columns name, table names, etc, not for data (use tds_get_char_data instead) * @return bytes written to \a dest * @param tds connection information * @param string_len length of string to read from wire * (in server characters, bytes for tds4-tds5, ucs2 for tds7+) * @param dest destination buffer, if NULL string is read and discarded * @param dest_size destination buffer size, in bytes */ int tds_get_string(TDSSOCKET * tds, int string_len, char *dest, size_t dest_size) { size_t wire_bytes; /* * FIX: 02-Jun-2000 by Scott C. Gray (SCG) * Bug to malloc(0) on some platforms. */ if (string_len == 0) { return 0; } assert(string_len >= 0 && dest_size >= 0); wire_bytes = IS_TDS7_PLUS(tds) ? string_len * 2 : string_len; if (IS_TDS7_PLUS(tds)) { if (dest == NULL) { tds_get_n(tds, NULL, (int)wire_bytes); return string_len; } return read_and_convert(tds, tds->char_convs[client2ucs2], &wire_bytes, &dest, &dest_size); } else { /* FIXME convert to client charset */ assert(dest_size >= (size_t) string_len); tds_get_n(tds, dest, string_len); return string_len; } }
/** * Fetch character data the wire. * Output is NOT null terminated. * If \a char_conv is not NULL, convert data accordingly. * \param tds state information for the socket and the TDS protocol * \param row_buffer destination buffer in current_row. Can't be NULL * \param wire_size size to read from wire (in bytes) * \param curcol column information * \return TDS_SUCCEED or TDS_FAIL (probably memory error on text data) * \todo put a TDSICONV structure in every TDSCOLUMN */ int tds_get_char_data(TDSSOCKET * tds, char *row_buffer, size_t wire_size, TDSCOLUMN * curcol) { size_t in_left; TDSBLOB *blob = NULL; char *dest = row_buffer; if (is_blob_col(curcol)) { blob = (TDSBLOB *) row_buffer; dest = blob->textvalue; } /* * dest is usually a column buffer, allocated when the column's metadata are processed * and reused for each row. * For blobs, dest is blob->textvalue, and can be reallocated or freed * TODO: reallocate if blob and no space */ /* silly case, empty string */ if (wire_size == 0) { curcol->column_cur_size = 0; if (blob) TDS_ZERO_FREE(blob->textvalue); return TDS_SUCCEED; } if (curcol->char_conv) { /* * TODO The conversion should be selected from curcol and tds version * TDS8/single -> use curcol collation * TDS7/single -> use server single byte * TDS7+/unicode -> use server (always unicode) * TDS5/4.2 -> use server * TDS5/UTF-8 -> use server * TDS5/UTF-16 -> use UTF-16 */ in_left = blob ? curcol->column_cur_size : curcol->column_size; curcol->column_cur_size = read_and_convert(tds, curcol->char_conv, &wire_size, &dest, &in_left); if (wire_size > 0) { tdsdump_log(TDS_DBG_NETWORK, "error: tds_get_char_data: discarded %u on wire while reading %d into client. \n", (unsigned int) wire_size, curcol->column_cur_size); return TDS_FAIL; } } else { curcol->column_cur_size = (TDS_INT)wire_size; if (tds_get_n(tds, dest, (int)wire_size) == NULL) { tdsdump_log(TDS_DBG_NETWORK, "error: tds_get_char_data: failed to read %u from wire. \n", (unsigned int) wire_size); return TDS_FAIL; } } return TDS_SUCCEED; }
/** * Fetch a string from the wire. * Output string is NOT null terminated. * If TDS version is 7 or 8 read unicode string and convert it. * This function should be use to read server default encoding strings like * columns name, table names, etc, not for data (use tds_get_char_data instead) * @return bytes written to \a dest * @param tds connection information * @param string_len length of string to read from wire * (in server characters, bytes for tds4-tds5, ucs2 for tds7+) * @param dest destination buffer, if NULL string is read and discarded * @param dest_size destination buffer size, in bytes */ size_t tds_get_string(TDSSOCKET * tds, size_t string_len, char *dest, size_t dest_size) { size_t wire_bytes = string_len; unsigned conv = client2server_chardata; if (IS_TDS7_PLUS(tds->conn)) { wire_bytes *= 2u; conv = client2ucs2; } if (dest == NULL) { tds_get_n(tds, NULL, wire_bytes); return string_len; } return read_and_convert(tds, tds->conn->char_convs[conv], &wire_bytes, dest, dest_size); }