mirror of
https://github.com/FirebirdSQL/firebird.git
synced 2025-01-24 21:23:04 +01:00
331 lines
8.6 KiB
C++
331 lines
8.6 KiB
C++
/*
|
|
* PROGRAM: JRD Remote Interface/Server
|
|
* MODULE: parse.cpp
|
|
* DESCRIPTION: BLR parser
|
|
*
|
|
* The contents of this file are subject to the Interbase Public
|
|
* License Version 1.0 (the "License"); you may not use this file
|
|
* except in compliance with the License. You may obtain a copy
|
|
* of the License at http://www.Inprise.com/IPL.html
|
|
*
|
|
* Software distributed under the License is distributed on an
|
|
* "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, either express
|
|
* or implied. See the License for the specific language governing
|
|
* rights and limitations under the License.
|
|
*
|
|
* The Original Code was created by Inprise Corporation
|
|
* and its predecessors. Portions created by Inprise Corporation are
|
|
* Copyright (C) Inprise Corporation.
|
|
*
|
|
* All Rights Reserved.
|
|
* Contributor(s): ______________________________________.
|
|
*/
|
|
|
|
#include "firebird.h"
|
|
#include <string.h>
|
|
#include <stdlib.h>
|
|
#include <stdio.h>
|
|
#include "../jrd/ibase.h"
|
|
#include "../remote/remote.h"
|
|
#include "../jrd/align.h"
|
|
#include "../jrd/gdsassert.h"
|
|
#include "../remote/parse_proto.h"
|
|
|
|
#if !defined(DEV_BUILD) || (defined(DEV_BUILD) && defined(WIN_NT))
|
|
#include "../jrd/gds_proto.h" /* gds__log() */
|
|
#endif
|
|
|
|
|
|
|
|
REM_MSG PARSE_messages(const UCHAR* blr, USHORT blr_length)
|
|
{
|
|
/**************************************
|
|
*
|
|
* P A R S E _ m e s s a g e s
|
|
*
|
|
**************************************
|
|
*
|
|
* Functional description
|
|
* Parse the messages of a blr request. For each message, allocate
|
|
* a message (msg) and a format (fmt) block. Return the number of
|
|
* messages found. If an error occurs, return -1;
|
|
*
|
|
**************************************/
|
|
REM_MSG next;
|
|
|
|
const SSHORT version = *blr++;
|
|
if ((version != blr_version4) && (version != blr_version5))
|
|
return (REM_MSG) - 1;
|
|
|
|
if (*blr++ != blr_begin)
|
|
return 0;
|
|
|
|
REM_MSG message = NULL;
|
|
USHORT net_length = 0;
|
|
|
|
while (*blr++ == blr_message) {
|
|
const USHORT msg_number = *blr++;
|
|
USHORT count = *blr++;
|
|
count += (*blr++) << 8;
|
|
rem_fmt* const format = new rem_fmt(count);
|
|
#ifdef DEBUG_REMOTE_MEMORY
|
|
printf("PARSE_messages allocate format %x\n", format);
|
|
#endif
|
|
format->fmt_count = count;
|
|
USHORT offset = 0;
|
|
for (dsc* desc = format->fmt_desc.begin(); count; --count, ++desc) {
|
|
USHORT align = 4;
|
|
switch (*blr++) {
|
|
case blr_text:
|
|
desc->dsc_dtype = dtype_text;
|
|
desc->dsc_length = *blr++;
|
|
desc->dsc_length += (*blr++) << 8;
|
|
align = type_alignments[dtype_text];
|
|
break;
|
|
|
|
case blr_varying:
|
|
desc->dsc_dtype = dtype_varying;
|
|
desc->dsc_length = *blr++ + sizeof(SSHORT);
|
|
desc->dsc_length += (*blr++) << 8;
|
|
align = type_alignments[dtype_varying];
|
|
break;
|
|
|
|
case blr_cstring:
|
|
desc->dsc_dtype = dtype_cstring;
|
|
desc->dsc_length = *blr++;
|
|
desc->dsc_length += (*blr++) << 8;
|
|
align = type_alignments[dtype_cstring];
|
|
break;
|
|
|
|
/* Parse the tagged blr types correctly */
|
|
|
|
case blr_text2:
|
|
desc->dsc_dtype = dtype_text;
|
|
desc->dsc_scale = *blr++;
|
|
desc->dsc_scale += (*blr++) << 8;
|
|
desc->dsc_length = *blr++;
|
|
desc->dsc_length += (*blr++) << 8;
|
|
align = type_alignments[dtype_text];
|
|
break;
|
|
|
|
case blr_varying2:
|
|
desc->dsc_dtype = dtype_varying;
|
|
desc->dsc_scale = *blr++;
|
|
desc->dsc_scale += (*blr++) << 8;
|
|
desc->dsc_length = *blr++ + sizeof(SSHORT);
|
|
desc->dsc_length += (*blr++) << 8;
|
|
align = type_alignments[dtype_varying];
|
|
break;
|
|
|
|
case blr_cstring2:
|
|
desc->dsc_dtype = dtype_cstring;
|
|
desc->dsc_scale = *blr++;
|
|
desc->dsc_scale += (*blr++) << 8;
|
|
desc->dsc_length = *blr++;
|
|
desc->dsc_length += (*blr++) << 8;
|
|
align = type_alignments[dtype_cstring];
|
|
break;
|
|
|
|
case blr_short:
|
|
desc->dsc_dtype = dtype_short;
|
|
desc->dsc_length = sizeof(SSHORT);
|
|
desc->dsc_scale = *blr++;
|
|
align = type_alignments[dtype_short];
|
|
break;
|
|
|
|
case blr_long:
|
|
desc->dsc_dtype = dtype_long;
|
|
desc->dsc_length = sizeof(SLONG);
|
|
desc->dsc_scale = *blr++;
|
|
align = type_alignments[dtype_long];
|
|
break;
|
|
|
|
case blr_int64:
|
|
desc->dsc_dtype = dtype_int64;
|
|
desc->dsc_length = sizeof(SINT64);
|
|
desc->dsc_scale = *blr++;
|
|
align = type_alignments[dtype_int64];
|
|
break;
|
|
|
|
case blr_quad:
|
|
desc->dsc_dtype = dtype_quad;
|
|
desc->dsc_length = sizeof(SLONG) * 2;
|
|
desc->dsc_scale = *blr++;
|
|
align = type_alignments[dtype_quad];
|
|
break;
|
|
|
|
case blr_float:
|
|
desc->dsc_dtype = dtype_real;
|
|
desc->dsc_length = sizeof(float);
|
|
align = type_alignments[dtype_real];
|
|
break;
|
|
|
|
case blr_double:
|
|
case blr_d_float:
|
|
desc->dsc_dtype = dtype_double;
|
|
desc->dsc_length = sizeof(double);
|
|
align = type_alignments[dtype_double];
|
|
break;
|
|
|
|
/* this case cannot occur as switch paramater is char and blr_blob
|
|
is 261. blob_ids are actually passed around as blr_quad.
|
|
|
|
case blr_blob:
|
|
desc->dsc_dtype = dtype_blob;
|
|
desc->dsc_length = sizeof (SLONG) * 2;
|
|
align = type_alignments [dtype_blob];
|
|
break;
|
|
*/
|
|
case blr_blob2:
|
|
{
|
|
desc->dsc_dtype = dtype_blob;
|
|
desc->dsc_length = sizeof(SLONG) * 2;
|
|
desc->dsc_sub_type = *blr++;
|
|
desc->dsc_sub_type += (*blr++) << 8;
|
|
|
|
USHORT textType = *blr++;
|
|
textType += (*blr++) << 8;
|
|
desc->setTextType(textType);
|
|
|
|
align = type_alignments[dtype_blob];
|
|
}
|
|
break;
|
|
|
|
case blr_timestamp:
|
|
desc->dsc_dtype = dtype_timestamp;
|
|
desc->dsc_length = sizeof(SLONG) * 2;
|
|
align = type_alignments[dtype_timestamp];
|
|
break;
|
|
|
|
case blr_sql_date:
|
|
desc->dsc_dtype = dtype_sql_date;
|
|
desc->dsc_length = sizeof(SLONG);
|
|
align = type_alignments[dtype_sql_date];
|
|
break;
|
|
|
|
case blr_sql_time:
|
|
desc->dsc_dtype = dtype_sql_time;
|
|
desc->dsc_length = sizeof(ULONG);
|
|
align = type_alignments[dtype_sql_time];
|
|
break;
|
|
|
|
default:
|
|
fb_assert(FALSE);
|
|
delete format;
|
|
while (next = message) {
|
|
message = message->msg_next;
|
|
delete next->msg_address;
|
|
delete next;
|
|
}
|
|
return (REM_MSG) - 1;
|
|
}
|
|
if (desc->dsc_dtype == dtype_varying)
|
|
net_length += 4 + ((desc->dsc_length - 2 + 3) & ~3);
|
|
else
|
|
net_length += (desc->dsc_length + 3) & ~3;
|
|
if (align > 1)
|
|
offset = FB_ALIGN(offset, align);
|
|
desc->dsc_address = (UCHAR*) (IPTR) offset;
|
|
offset += desc->dsc_length;
|
|
}
|
|
format->fmt_length = offset;
|
|
format->fmt_net_length = net_length;
|
|
next = new Message(format->fmt_length);
|
|
#ifdef DEBUG_REMOTE_MEMORY
|
|
printf("PARSE_messages allocate message %x\n", next);
|
|
#endif
|
|
next->msg_next = message;
|
|
message = next;
|
|
message->msg_address = reinterpret_cast<UCHAR*>(format);
|
|
message->msg_number = msg_number;
|
|
}
|
|
|
|
return message;
|
|
}
|
|
|
|
|
|
const UCHAR* PARSE_prepare_messages(const UCHAR* blr, USHORT blr_length)
|
|
{
|
|
/**************************************
|
|
*
|
|
* P A R S E _ p r e p a r e _ m e s s a g e s
|
|
*
|
|
**************************************
|
|
*
|
|
* Functional description
|
|
* Parse the messages of a blr request and convert
|
|
* each occurrence of blr_d_float to blr_double.
|
|
*
|
|
* This function is only called for protocol version 5 and below
|
|
*
|
|
**************************************/
|
|
const UCHAR* old_blr = blr;
|
|
const UCHAR* new_blr = blr;
|
|
|
|
const SSHORT version = *blr++;
|
|
if (((version != blr_version4) && (version != blr_version5)) ||
|
|
*blr++ != blr_begin)
|
|
{
|
|
return old_blr;
|
|
}
|
|
|
|
while (*blr++ == blr_message) {
|
|
blr++;
|
|
USHORT count = *blr++;
|
|
count += (*blr++) << 8;
|
|
for (; count; --count)
|
|
switch (*blr++) {
|
|
case blr_text2:
|
|
case blr_varying2:
|
|
case blr_cstring2:
|
|
blr += 4; /* SUBTYPE word & LENGTH word */
|
|
break;
|
|
case blr_text:
|
|
case blr_varying:
|
|
case blr_cstring:
|
|
blr += 2; /* LENGTH word */
|
|
break;
|
|
case blr_short:
|
|
case blr_long:
|
|
case blr_int64:
|
|
case blr_quad:
|
|
blr++; /* SCALE byte */
|
|
break;
|
|
case blr_float:
|
|
case blr_double:
|
|
case blr_timestamp:
|
|
case blr_sql_date:
|
|
case blr_sql_time:
|
|
break;
|
|
|
|
case blr_d_float:
|
|
if (new_blr == old_blr) {
|
|
new_blr = FB_NEW(*getDefaultMemoryPool()) UCHAR[blr_length];
|
|
/* FREE: Never freed, blr_d_float is VMS specific */
|
|
#ifdef DEBUG_REMOTE_MEMORY
|
|
printf
|
|
("PARSE_prepare_messages allocate blr %x\n",
|
|
new_blr);
|
|
#endif
|
|
// Safe const_cast, we are allocating new space for new_blr
|
|
memcpy(const_cast<UCHAR*>(new_blr), old_blr, blr_length);
|
|
blr = new_blr + (int) (blr - old_blr);
|
|
}
|
|
|
|
// It's safe because blr has been replaced by new space,
|
|
// we aren't overwriting the original const parameter.
|
|
fb_assert(new_blr != old_blr);
|
|
const_cast<UCHAR*>(blr)[-1] = blr_double;
|
|
break;
|
|
|
|
default:
|
|
DEV_REPORT("Unexpected BLR in PARSE_prepare_messages()");
|
|
/* This old code would return, so we will also */
|
|
return new_blr;
|
|
}
|
|
}
|
|
|
|
return new_blr;
|
|
}
|
|
|