mirror of
https://github.com/FirebirdSQL/firebird.git
synced 2025-01-30 19:23:03 +01:00
139331c7e3
plain new to FB_NEW, making allocated with it blocks tagged with file/line. Make related code slightly better readable.
362 lines
8.1 KiB
C++
362 lines
8.1 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 "../common/gdsassert.h"
|
|
#include "../remote/parse_proto.h"
|
|
|
|
#if !defined(DEV_BUILD) || (defined(DEV_BUILD) && defined(WIN_NT))
|
|
#include "../yvalve/gds_proto.h" // gds__log()
|
|
#endif
|
|
|
|
|
|
static rem_fmt* parse_format(const UCHAR*& blr, size_t& blr_length);
|
|
|
|
|
|
RMessage* PARSE_messages(const UCHAR* blr, size_t 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.
|
|
*
|
|
**************************************/
|
|
|
|
if (blr_length < 3)
|
|
return NULL;
|
|
blr_length -= 3;
|
|
|
|
const SSHORT version = *blr++;
|
|
if (version != blr_version4 && version != blr_version5)
|
|
return NULL;
|
|
|
|
if (*blr++ != blr_begin)
|
|
return NULL;
|
|
|
|
RMessage* message = NULL;
|
|
ULONG net_length = 0;
|
|
|
|
bool error = false;
|
|
|
|
while (*blr++ == blr_message)
|
|
{
|
|
if (blr_length-- == 0)
|
|
{
|
|
error = true;
|
|
break;
|
|
}
|
|
|
|
const USHORT msg_number = *blr++;
|
|
|
|
rem_fmt* const format = parse_format(blr, blr_length);
|
|
if (!format)
|
|
{
|
|
error = true;
|
|
break;
|
|
}
|
|
|
|
RMessage* next = FB_NEW RMessage(format->fmt_length);
|
|
next->msg_next = message;
|
|
message = next;
|
|
message->msg_address = reinterpret_cast<UCHAR*>(format);
|
|
message->msg_number = msg_number;
|
|
|
|
if (blr_length-- == 0)
|
|
{
|
|
error = true;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (error)
|
|
{
|
|
for (RMessage* next = message; next; next = message)
|
|
{
|
|
message = message->msg_next;
|
|
delete next->msg_address;
|
|
delete next;
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
return message;
|
|
}
|
|
|
|
|
|
rem_fmt* PARSE_msg_format(const UCHAR* blr, size_t blr_length)
|
|
{
|
|
/**************************************
|
|
*
|
|
* P A R S E _ m s g _ f o r m a t
|
|
*
|
|
**************************************
|
|
*
|
|
* Functional description
|
|
* Parse the message of a blr request and return its format.
|
|
*
|
|
**************************************/
|
|
|
|
if (blr_length < 4)
|
|
return NULL;
|
|
blr_length -= 4;
|
|
|
|
const SSHORT version = *blr++;
|
|
if (version != blr_version4 && version != blr_version5)
|
|
return NULL;
|
|
|
|
if (*blr++ != blr_begin)
|
|
return NULL;
|
|
|
|
if (*blr++ != blr_message)
|
|
return NULL;
|
|
|
|
blr++; // skip message number
|
|
|
|
return parse_format(blr, blr_length);
|
|
}
|
|
|
|
static rem_fmt* parse_format(const UCHAR*& blr, size_t& blr_length)
|
|
{
|
|
if (blr_length < 2)
|
|
return NULL;
|
|
blr_length -= 2;
|
|
|
|
USHORT count = *blr++;
|
|
count += (*blr++) << 8;
|
|
|
|
Firebird::AutoPtr<rem_fmt> format(FB_NEW rem_fmt(count));
|
|
|
|
ULONG net_length = 0;
|
|
ULONG offset = 0;
|
|
|
|
for (dsc* desc = format->fmt_desc.begin(); count; --count, ++desc)
|
|
{
|
|
if (blr_length-- == 0)
|
|
return NULL;
|
|
|
|
USHORT align = 4;
|
|
switch (*blr++)
|
|
{
|
|
case blr_text:
|
|
if (blr_length < 2)
|
|
return NULL;
|
|
blr_length -= 2;
|
|
desc->dsc_dtype = dtype_text;
|
|
desc->dsc_length = *blr++;
|
|
desc->dsc_length += (*blr++) << 8;
|
|
align = type_alignments[dtype_text];
|
|
break;
|
|
|
|
case blr_varying:
|
|
if (blr_length < 2)
|
|
return NULL;
|
|
blr_length -= 2;
|
|
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:
|
|
if (blr_length < 2)
|
|
return NULL;
|
|
blr_length -= 2;
|
|
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:
|
|
if (blr_length < 4)
|
|
return NULL;
|
|
blr_length -= 4;
|
|
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:
|
|
if (blr_length < 4)
|
|
return NULL;
|
|
blr_length -= 4;
|
|
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:
|
|
if (blr_length < 4)
|
|
return NULL;
|
|
blr_length -= 4;
|
|
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:
|
|
if (blr_length-- == 0)
|
|
return NULL;
|
|
desc->dsc_dtype = dtype_short;
|
|
desc->dsc_length = sizeof(SSHORT);
|
|
desc->dsc_scale = *blr++;
|
|
align = type_alignments[dtype_short];
|
|
break;
|
|
|
|
case blr_long:
|
|
if (blr_length-- == 0)
|
|
return NULL;
|
|
desc->dsc_dtype = dtype_long;
|
|
desc->dsc_length = sizeof(SLONG);
|
|
desc->dsc_scale = *blr++;
|
|
align = type_alignments[dtype_long];
|
|
break;
|
|
|
|
case blr_int64:
|
|
if (blr_length-- == 0)
|
|
return NULL;
|
|
desc->dsc_dtype = dtype_int64;
|
|
desc->dsc_length = sizeof(SINT64);
|
|
desc->dsc_scale = *blr++;
|
|
align = type_alignments[dtype_int64];
|
|
break;
|
|
|
|
case blr_quad:
|
|
if (blr_length-- == 0)
|
|
return NULL;
|
|
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:
|
|
{
|
|
if (blr_length < 4)
|
|
return NULL;
|
|
blr_length -= 4;
|
|
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;
|
|
|
|
case blr_bool:
|
|
desc->dsc_dtype = dtype_boolean;
|
|
desc->dsc_length = sizeof(UCHAR);
|
|
align = type_alignments[dtype_boolean];
|
|
break;
|
|
|
|
default:
|
|
fb_assert(false);
|
|
return NULL;
|
|
}
|
|
|
|
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;
|
|
|
|
return format.release();
|
|
}
|