2005-05-28 00:45:31 +02:00
|
|
|
/*
|
|
|
|
*
|
2008-04-29 13:23:06 +02:00
|
|
|
* The contents of this file are subject to the Initial
|
|
|
|
* Developer's 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.ibphoenix.com/idpl.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
|
2005-05-28 00:45:31 +02:00
|
|
|
* language governing rights and limitations under the License.
|
|
|
|
*
|
|
|
|
* The contents of this file or any work derived from this file
|
2008-04-29 13:23:06 +02:00
|
|
|
* may not be distributed under any other license whatsoever
|
|
|
|
* without the express prior written permission of the original
|
2005-05-28 00:45:31 +02:00
|
|
|
* author.
|
|
|
|
*
|
|
|
|
*
|
|
|
|
* The Original Code was created by James A. Starkey for IBPhoenix.
|
|
|
|
*
|
|
|
|
* Copyright (c) 1997 - 2000, 2001, 2003 James A. Starkey
|
|
|
|
* Copyright (c) 1997 - 2000, 2001, 2003 Netfrastructure, Inc.
|
|
|
|
* All Rights Reserved.
|
|
|
|
*/
|
|
|
|
|
|
|
|
// Stream.cpp: implementation of the Stream class.
|
|
|
|
//
|
|
|
|
//////////////////////////////////////////////////////////////////////
|
|
|
|
|
|
|
|
#include <memory.h>
|
|
|
|
#include <string.h>
|
|
|
|
#include <stdio.h>
|
|
|
|
#include <stdarg.h>
|
|
|
|
#include "firebird.h"
|
2006-06-16 14:36:09 +02:00
|
|
|
#include "../common/classes/alloc.h"
|
2005-05-28 00:45:31 +02:00
|
|
|
#include "Stream.h"
|
|
|
|
#include "StreamSegment.h"
|
|
|
|
|
2008-04-20 12:40:58 +02:00
|
|
|
|
|
|
|
// CVC: The logic in this module seems to overwrite constant params passed into the
|
|
|
|
// address field of the Segment structure. This includes literal strings (see Element.cpp).
|
|
|
|
|
2005-05-28 00:45:31 +02:00
|
|
|
#ifndef MAX
|
|
|
|
#define MAX(a,b) ((a > b) ? a : b)
|
|
|
|
#define MIN(a,b) ((a < b) ? a : b)
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#ifdef _DEBUG
|
|
|
|
#undef THIS_FILE
|
2008-04-29 13:23:06 +02:00
|
|
|
static char THIS_FILE[] = __FILE__;
|
2005-05-28 00:45:31 +02:00
|
|
|
#endif
|
|
|
|
|
|
|
|
//////////////////////////////////////////////////////////////////////
|
|
|
|
// Construction/Destruction
|
|
|
|
//////////////////////////////////////////////////////////////////////
|
|
|
|
|
|
|
|
Stream::Stream(int minSegmentSize)
|
|
|
|
{
|
|
|
|
segments = NULL;
|
|
|
|
current = NULL;
|
|
|
|
totalLength = 0;
|
|
|
|
minSegment = minSegmentSize;
|
|
|
|
copyFlag = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
Stream::~Stream()
|
|
|
|
{
|
|
|
|
clear();
|
|
|
|
}
|
|
|
|
|
|
|
|
void Stream::putCharacter(char c)
|
|
|
|
{
|
|
|
|
if (!segments || current->length >= currentLength)
|
|
|
|
allocSegment (MAX (100, minSegment));
|
|
|
|
|
|
|
|
current->address [current->length] = c;
|
|
|
|
++current->length;
|
|
|
|
++totalLength;
|
|
|
|
}
|
|
|
|
|
|
|
|
void Stream::putSegment(int length, const char *ptr, bool copy)
|
|
|
|
{
|
|
|
|
#ifdef ENGINE
|
|
|
|
ASSERT (length >= 0);
|
|
|
|
#endif
|
|
|
|
if (length == 0)
|
|
|
|
return;
|
|
|
|
|
2008-04-19 11:40:19 +02:00
|
|
|
const char *address = ptr;
|
2005-05-28 00:45:31 +02:00
|
|
|
totalLength += length;
|
|
|
|
|
|
|
|
if (!segments)
|
2008-04-29 13:23:06 +02:00
|
|
|
{
|
2005-05-28 00:45:31 +02:00
|
|
|
if (copyFlag = copy)
|
2008-04-29 13:23:06 +02:00
|
|
|
{
|
2005-05-28 00:45:31 +02:00
|
|
|
allocSegment (MAX (length, minSegment));
|
|
|
|
current->length = length;
|
|
|
|
memcpy (current->address, address, length);
|
2008-04-29 13:23:06 +02:00
|
|
|
}
|
2005-05-28 00:45:31 +02:00
|
|
|
else
|
2008-04-29 13:23:06 +02:00
|
|
|
{
|
2005-05-28 00:45:31 +02:00
|
|
|
//copyFlag = copy;
|
|
|
|
current = segments = &first;
|
|
|
|
current->length = length;
|
|
|
|
current->address = (char*) address;
|
|
|
|
current->next = NULL;
|
|
|
|
}
|
2008-04-29 13:23:06 +02:00
|
|
|
}
|
2005-05-28 00:45:31 +02:00
|
|
|
else if (copyFlag)
|
2008-04-29 13:23:06 +02:00
|
|
|
{
|
2005-05-28 00:45:31 +02:00
|
|
|
int l = currentLength - current->length;
|
|
|
|
if (l > 0)
|
2008-04-29 13:23:06 +02:00
|
|
|
{
|
2008-04-20 12:40:58 +02:00
|
|
|
const int l2 = MIN (l, length);
|
2005-05-28 00:45:31 +02:00
|
|
|
memcpy (current->address + current->length, address, l2);
|
|
|
|
current->length += l2;
|
|
|
|
length -= l2;
|
|
|
|
address += l2;
|
2008-04-29 13:23:06 +02:00
|
|
|
}
|
2005-05-28 00:45:31 +02:00
|
|
|
if (length)
|
2008-04-29 13:23:06 +02:00
|
|
|
{
|
2005-05-28 00:45:31 +02:00
|
|
|
allocSegment (MAX (length, minSegment));
|
|
|
|
current->length = length;
|
|
|
|
memcpy (current->address, address, length);
|
|
|
|
}
|
2008-04-29 13:23:06 +02:00
|
|
|
}
|
2005-05-28 00:45:31 +02:00
|
|
|
else
|
2008-04-29 13:23:06 +02:00
|
|
|
{
|
2005-05-28 00:45:31 +02:00
|
|
|
allocSegment (0);
|
|
|
|
current->address = (char*) address;
|
|
|
|
current->length = length;
|
2008-04-29 13:23:06 +02:00
|
|
|
}
|
2005-05-28 00:45:31 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2008-04-29 13:23:06 +02:00
|
|
|
int Stream::getSegment(int offset, int len, void* ptr) const
|
2005-05-28 00:45:31 +02:00
|
|
|
{
|
|
|
|
int n = 0;
|
|
|
|
int length = len;
|
2008-04-29 13:23:06 +02:00
|
|
|
char* address = static_cast<char*>(ptr);
|
2005-05-28 00:45:31 +02:00
|
|
|
|
2008-04-19 11:40:19 +02:00
|
|
|
for (const Segment *segment = segments; segment; n += segment->length, segment = segment->next)
|
|
|
|
{
|
2005-05-28 00:45:31 +02:00
|
|
|
if (n + segment->length >= offset)
|
2008-04-19 11:40:19 +02:00
|
|
|
{
|
|
|
|
const int off = offset - n;
|
|
|
|
const int l = MIN (length, segment->length - off);
|
2005-05-28 00:45:31 +02:00
|
|
|
memcpy (address, segment->address + off, l);
|
|
|
|
address += l;
|
|
|
|
length -= l;
|
|
|
|
offset += l;
|
|
|
|
if (!length)
|
|
|
|
break;
|
2008-04-19 11:40:19 +02:00
|
|
|
}
|
|
|
|
}
|
2005-05-28 00:45:31 +02:00
|
|
|
|
|
|
|
return len - length;
|
|
|
|
}
|
|
|
|
|
|
|
|
void Stream::setSegment(Segment * segment, int length, void* address)
|
|
|
|
{
|
|
|
|
segment->length = length;
|
|
|
|
totalLength += length;
|
|
|
|
|
|
|
|
if (copyFlag)
|
2008-04-29 13:23:06 +02:00
|
|
|
{
|
2005-05-28 00:45:31 +02:00
|
|
|
segment->address = new char [length];
|
|
|
|
memcpy (segment->address, address, length);
|
2008-04-29 13:23:06 +02:00
|
|
|
}
|
2005-05-28 00:45:31 +02:00
|
|
|
else
|
|
|
|
segment->address = (char*) address;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void Stream::setMinSegment(int length)
|
|
|
|
{
|
|
|
|
minSegment = length;
|
|
|
|
}
|
|
|
|
|
2008-04-29 13:23:06 +02:00
|
|
|
Stream::Segment* Stream::allocSegment(int tail)
|
2005-05-28 00:45:31 +02:00
|
|
|
{
|
2008-04-29 13:23:06 +02:00
|
|
|
fb_assert(tail >= 0);
|
|
|
|
|
2005-05-28 00:45:31 +02:00
|
|
|
Segment *segment;
|
|
|
|
int length = tail;
|
|
|
|
|
|
|
|
if (!current && tail <= FIXED_SEGMENT_SIZE)
|
2008-04-29 13:23:06 +02:00
|
|
|
{
|
2005-05-28 00:45:31 +02:00
|
|
|
segment = &first;
|
|
|
|
length = FIXED_SEGMENT_SIZE;
|
2008-04-29 13:23:06 +02:00
|
|
|
}
|
2005-05-28 00:45:31 +02:00
|
|
|
else
|
2008-04-29 13:23:06 +02:00
|
|
|
{
|
|
|
|
// CVC: What do we do here in the release build if tail is smaller than FIXED_SEGMENT_SIZE?
|
|
|
|
fb_assert(tail >= FIXED_SEGMENT_SIZE);
|
|
|
|
segment = (Segment*) new char [sizeof(Segment) + tail - FIXED_SEGMENT_SIZE];
|
|
|
|
}
|
2005-05-28 00:45:31 +02:00
|
|
|
|
|
|
|
segment->address = segment->tail;
|
|
|
|
segment->next = NULL;
|
|
|
|
segment->length = 0;
|
|
|
|
currentLength = length;
|
|
|
|
|
|
|
|
if (current)
|
2008-04-29 13:23:06 +02:00
|
|
|
{
|
2005-05-28 00:45:31 +02:00
|
|
|
current->next = segment;
|
|
|
|
current = segment;
|
2008-04-29 13:23:06 +02:00
|
|
|
}
|
2005-05-28 00:45:31 +02:00
|
|
|
else
|
|
|
|
segments = current = segment;
|
|
|
|
|
|
|
|
return segment;
|
|
|
|
}
|
|
|
|
|
2008-04-19 11:40:19 +02:00
|
|
|
int Stream::getSegment(int offset, int len, void * ptr, char delimiter) const
|
2005-05-28 00:45:31 +02:00
|
|
|
{
|
|
|
|
int n = 0;
|
|
|
|
int length = len;
|
2008-04-29 13:23:06 +02:00
|
|
|
char *address = static_cast<char*>(ptr);
|
2005-05-28 00:45:31 +02:00
|
|
|
|
2008-04-19 11:40:19 +02:00
|
|
|
for (const Segment *segment = segments; segment; n += segment->length, segment = segment->next)
|
|
|
|
{
|
2005-05-28 00:45:31 +02:00
|
|
|
if (n + segment->length >= offset)
|
2008-04-19 11:40:19 +02:00
|
|
|
{
|
|
|
|
const int off = offset - n;
|
|
|
|
const int l = MIN (length, segment->length - off);
|
|
|
|
const char *p = segment->address + off;
|
|
|
|
for (const char *end = p + l; p < end;)
|
2008-04-29 13:23:06 +02:00
|
|
|
{
|
2008-04-19 11:40:19 +02:00
|
|
|
const char c = *address++ = *p++;
|
2005-05-28 00:45:31 +02:00
|
|
|
--length;
|
|
|
|
if (c == delimiter)
|
|
|
|
return len - length;
|
2008-04-29 13:23:06 +02:00
|
|
|
}
|
2005-05-28 00:45:31 +02:00
|
|
|
if (!length)
|
|
|
|
break;
|
2008-04-19 11:40:19 +02:00
|
|
|
}
|
|
|
|
}
|
2005-05-28 00:45:31 +02:00
|
|
|
|
|
|
|
return len - length;
|
|
|
|
}
|
|
|
|
|
|
|
|
void Stream::putSegment(const char * string)
|
|
|
|
{
|
|
|
|
if (string [0])
|
|
|
|
putSegment ((int) strlen (string), string, true);
|
|
|
|
}
|
|
|
|
|
|
|
|
char* Stream::getString()
|
|
|
|
{
|
2008-04-19 11:40:19 +02:00
|
|
|
char* const string = new char [totalLength + 1];
|
2005-05-28 00:45:31 +02:00
|
|
|
getSegment (0, totalLength, string);
|
|
|
|
string [totalLength] = 0;
|
|
|
|
|
|
|
|
return string;
|
|
|
|
}
|
|
|
|
|
|
|
|
#ifdef ENGINE
|
2008-04-19 11:40:19 +02:00
|
|
|
void Stream::compress(int length, const void * address)
|
2005-05-28 00:45:31 +02:00
|
|
|
{
|
|
|
|
//printShorts ("Original data", (length + 1) / 2, (short*) address);
|
|
|
|
Segment *segment = allocSegment (length + 5);
|
|
|
|
short *q = (short*) segment->address;
|
2008-04-19 11:40:19 +02:00
|
|
|
const short *p = (short*) address;
|
2008-04-29 13:23:06 +02:00
|
|
|
const short* const end = p + (length + 1) / 2;
|
2008-04-19 11:40:19 +02:00
|
|
|
const short* const yellow = end - 2;
|
2005-05-28 00:45:31 +02:00
|
|
|
*q++ = length;
|
|
|
|
|
|
|
|
while (p < end)
|
2008-04-29 13:23:06 +02:00
|
|
|
{
|
2005-05-28 00:45:31 +02:00
|
|
|
short *start = ++q;
|
2008-04-29 13:23:06 +02:00
|
|
|
while (p < end && (p >= yellow || p[0] != p[1] || p[1] != p[2]))
|
2005-05-28 00:45:31 +02:00
|
|
|
*q++ = *p++;
|
|
|
|
int n = q - start;
|
|
|
|
if (n)
|
|
|
|
start [-1] = -n;
|
|
|
|
else
|
|
|
|
--q;
|
|
|
|
if (p >= end)
|
|
|
|
break;
|
2008-04-19 11:40:19 +02:00
|
|
|
const short* start2 = p++;
|
|
|
|
while (p < end && *p == *start2)
|
2005-05-28 00:45:31 +02:00
|
|
|
++p;
|
2008-04-19 11:40:19 +02:00
|
|
|
n = p - start2;
|
2005-05-28 00:45:31 +02:00
|
|
|
*q++ = n;
|
2008-04-19 11:40:19 +02:00
|
|
|
*q++ = *start2;
|
2008-04-29 13:23:06 +02:00
|
|
|
}
|
2005-05-28 00:45:31 +02:00
|
|
|
|
|
|
|
totalLength = segment->length = (char*) q - segment->address;
|
|
|
|
}
|
|
|
|
|
|
|
|
char* Stream::decompress(int tableId, int recordNumber)
|
|
|
|
{
|
|
|
|
char *data;
|
|
|
|
short *q, *limit;
|
|
|
|
int run = 0;
|
|
|
|
decompressedLength = 0;
|
|
|
|
|
|
|
|
for (Segment *segment = segments; segment; segment = segment->next)
|
2008-04-29 13:23:06 +02:00
|
|
|
{
|
2005-05-28 00:45:31 +02:00
|
|
|
if (segment->length == 0)
|
|
|
|
continue;
|
2008-04-29 13:23:06 +02:00
|
|
|
const short* p = (short*) segment->address;
|
|
|
|
const short* end = (short*) (segment->address + segment->length);
|
2005-05-28 00:45:31 +02:00
|
|
|
if (decompressedLength == 0)
|
2008-04-29 13:23:06 +02:00
|
|
|
{
|
2005-05-28 00:45:31 +02:00
|
|
|
decompressedLength = *p++;
|
|
|
|
if (decompressedLength <= 0)
|
2008-04-29 13:23:06 +02:00
|
|
|
{
|
|
|
|
Log::log ("corrupted record, table %d, record %d, decompressed length %d\n",
|
2005-05-28 00:45:31 +02:00
|
|
|
tableId, recordNumber, decompressedLength);
|
2008-04-29 13:23:06 +02:00
|
|
|
throw SQLEXCEPTION (RUNTIME_ERROR, "corrupted record, table %d, record %d, decompressed length %d",
|
2005-05-28 00:45:31 +02:00
|
|
|
tableId, recordNumber, decompressedLength);
|
2008-04-29 13:23:06 +02:00
|
|
|
}
|
2005-06-06 10:30:03 +02:00
|
|
|
int len = ((decompressedLength + 1) / 2) * 2;
|
2005-05-28 00:45:31 +02:00
|
|
|
//data = new char [len];
|
|
|
|
data = ALLOCATE_RECORD (len);
|
|
|
|
limit = (short*) (data + decompressedLength);
|
|
|
|
if (decompressedLength & 1)
|
|
|
|
++limit;
|
|
|
|
q = (short*) data;
|
2008-04-29 13:23:06 +02:00
|
|
|
}
|
2005-05-28 00:45:31 +02:00
|
|
|
while (p < end)
|
2008-04-29 13:23:06 +02:00
|
|
|
{
|
|
|
|
const short n = *p++;
|
2005-05-28 00:45:31 +02:00
|
|
|
//#ifdef ENGINE
|
|
|
|
if (n == 0 && run == 0)
|
2008-04-29 13:23:06 +02:00
|
|
|
{
|
2005-05-28 00:45:31 +02:00
|
|
|
Log::log ("corrupted record (zero run), table %d, record %d\n", tableId, recordNumber);
|
2005-06-06 10:30:03 +02:00
|
|
|
printShorts ("Zero run", (segment->length + 1) / 2, (short*) segment->address);
|
2005-05-28 00:45:31 +02:00
|
|
|
printChars ("Zero run", segment->length, segment->address);
|
2008-04-29 13:23:06 +02:00
|
|
|
}
|
2005-05-28 00:45:31 +02:00
|
|
|
//#endif
|
|
|
|
if (run > 0)
|
2008-04-29 13:23:06 +02:00
|
|
|
{
|
2005-05-28 00:45:31 +02:00
|
|
|
for (; run; --run)
|
|
|
|
*q++ = n;
|
2008-04-29 13:23:06 +02:00
|
|
|
}
|
2005-05-28 00:45:31 +02:00
|
|
|
else if (run < 0)
|
2008-04-29 13:23:06 +02:00
|
|
|
{
|
2005-05-28 00:45:31 +02:00
|
|
|
*q++ = n;
|
|
|
|
++run;
|
2008-04-29 13:23:06 +02:00
|
|
|
}
|
2005-05-28 00:45:31 +02:00
|
|
|
else
|
2008-04-29 13:23:06 +02:00
|
|
|
{
|
2005-05-28 00:45:31 +02:00
|
|
|
run = n;
|
|
|
|
if (q + run > limit)
|
2008-04-29 13:23:06 +02:00
|
|
|
{
|
2005-05-28 00:45:31 +02:00
|
|
|
//#ifdef ENGINE
|
|
|
|
Log::log ("corrupted record (overrun), table %d, record %d\n", tableId, recordNumber);
|
|
|
|
printShorts ("Compressed", (segment->length + 1)/2, (short*) segment->address);
|
|
|
|
printChars ("Compressed", segment->length, segment->address);
|
|
|
|
//#endif
|
|
|
|
if (q == limit)
|
|
|
|
return data;
|
|
|
|
throw SQLEXCEPTION (RUNTIME_ERROR, "corrupted record, table %d, record %d", tableId, recordNumber);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2008-04-29 13:23:06 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
//printShorts ("Decompressed", (decompressedLength + 1) / 2, (short*) data);
|
2005-05-28 00:45:31 +02:00
|
|
|
return data;
|
|
|
|
}
|
|
|
|
|
|
|
|
void Stream::printShorts(const char * msg, int length, short * data)
|
|
|
|
{
|
|
|
|
Log::debug ("%s", msg);
|
|
|
|
|
|
|
|
for (int n = 0; n < length; ++n)
|
2008-04-29 13:23:06 +02:00
|
|
|
{
|
2005-05-28 00:45:31 +02:00
|
|
|
if (n % 10 == 0)
|
|
|
|
Log::debug ("\n ");
|
|
|
|
Log::debug ("%d, ", data [n]);
|
2008-04-29 13:23:06 +02:00
|
|
|
}
|
2005-05-28 00:45:31 +02:00
|
|
|
|
|
|
|
Log::debug ("\n");
|
|
|
|
}
|
|
|
|
|
|
|
|
void Stream::printChars(const char * msg, int length, const char * data)
|
|
|
|
{
|
|
|
|
Log::debug ("%s", msg);
|
|
|
|
|
|
|
|
for (int n = 0; n < length; ++n)
|
2008-04-29 13:23:06 +02:00
|
|
|
{
|
2005-05-28 00:45:31 +02:00
|
|
|
if (n % 50 == 0)
|
|
|
|
Log::debug ("\n ");
|
2008-04-29 13:23:06 +02:00
|
|
|
const char c = data [n];
|
2005-05-28 00:45:31 +02:00
|
|
|
if ((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || (c >= '0' && c <= '9'))
|
|
|
|
putchar (c);
|
|
|
|
else
|
|
|
|
putchar ('.');
|
2008-04-29 13:23:06 +02:00
|
|
|
}
|
2005-05-28 00:45:31 +02:00
|
|
|
|
|
|
|
Log::debug ("\n");
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
void Stream::clear()
|
|
|
|
{
|
|
|
|
Segment *segment;
|
|
|
|
|
|
|
|
while (segment = segments)
|
2008-04-29 13:23:06 +02:00
|
|
|
{
|
2005-05-28 00:45:31 +02:00
|
|
|
segments = segment->next;
|
|
|
|
if (segment != &first)
|
2008-04-29 13:23:06 +02:00
|
|
|
delete[] (char*) segment;
|
|
|
|
}
|
2005-05-28 00:45:31 +02:00
|
|
|
|
|
|
|
current = NULL;
|
|
|
|
totalLength = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
void Stream::putSegment(int length, const unsigned short *chars)
|
|
|
|
{
|
|
|
|
if (length == 0)
|
|
|
|
return;
|
|
|
|
|
|
|
|
totalLength += length;
|
|
|
|
const unsigned short *wc = chars;
|
|
|
|
|
|
|
|
if (!segments)
|
2008-04-29 13:23:06 +02:00
|
|
|
{
|
2005-05-28 00:45:31 +02:00
|
|
|
allocSegment (MAX (length, minSegment));
|
|
|
|
current->length = length;
|
2008-04-29 13:23:06 +02:00
|
|
|
}
|
2005-05-28 00:45:31 +02:00
|
|
|
else
|
2008-04-29 13:23:06 +02:00
|
|
|
{
|
2005-05-28 00:45:31 +02:00
|
|
|
int l = currentLength - current->length;
|
|
|
|
if (l > 0)
|
2008-04-29 13:23:06 +02:00
|
|
|
{
|
|
|
|
const int l2 = MIN (l, length);
|
2005-05-28 00:45:31 +02:00
|
|
|
char *p = current->address + current->length;
|
|
|
|
for (int n = 0; n < l2; ++n)
|
|
|
|
*p++ = (char) *wc++;
|
|
|
|
//memcpy (current->address + current->length, address, l2);
|
|
|
|
current->length += l2;
|
|
|
|
length -= l2;
|
|
|
|
//address += l2;
|
2008-04-29 13:23:06 +02:00
|
|
|
}
|
2005-05-28 00:45:31 +02:00
|
|
|
if (length)
|
2008-04-29 13:23:06 +02:00
|
|
|
{
|
2005-05-28 00:45:31 +02:00
|
|
|
allocSegment (MAX (length, minSegment));
|
|
|
|
current->length = length;
|
|
|
|
//memcpy (current->address, address, length);
|
|
|
|
}
|
2008-04-29 13:23:06 +02:00
|
|
|
}
|
2005-05-28 00:45:31 +02:00
|
|
|
|
|
|
|
char *p = current->address;
|
|
|
|
|
|
|
|
for (int n = 0; n < length; ++n)
|
|
|
|
*p++ = (char) *wc++;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
2008-04-19 11:40:19 +02:00
|
|
|
int Stream::getLength() const
|
2005-05-28 00:45:31 +02:00
|
|
|
{
|
|
|
|
return totalLength;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2008-04-19 11:40:19 +02:00
|
|
|
int Stream::getSegmentLength(int offset) const
|
2005-05-28 00:45:31 +02:00
|
|
|
{
|
|
|
|
int n = 0;
|
|
|
|
|
2008-04-19 11:40:19 +02:00
|
|
|
for (const Segment *segment = segments; segment; segment = segment->next)
|
2008-04-29 13:23:06 +02:00
|
|
|
{
|
2005-05-28 00:45:31 +02:00
|
|
|
if (offset >= n && offset < n + segment->length)
|
|
|
|
return n + segment->length - offset;
|
|
|
|
n += segment->length;
|
2008-04-29 13:23:06 +02:00
|
|
|
}
|
2005-05-28 00:45:31 +02:00
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
void* Stream::getSegment(int offset)
|
|
|
|
{
|
|
|
|
int n = 0;
|
|
|
|
|
|
|
|
for (Segment *segment = segments; segment; segment = segment->next)
|
2008-04-29 13:23:06 +02:00
|
|
|
{
|
2005-05-28 00:45:31 +02:00
|
|
|
if (offset >= n && offset < n + segment->length)
|
|
|
|
return segment->address + offset - n;
|
|
|
|
n += segment->length;
|
2008-04-29 13:23:06 +02:00
|
|
|
}
|
2005-05-28 00:45:31 +02:00
|
|
|
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2008-04-19 11:40:19 +02:00
|
|
|
const void* Stream::getSegment(int offset) const
|
|
|
|
{
|
|
|
|
int n = 0;
|
|
|
|
|
|
|
|
for (const Segment *segment = segments; segment; segment = segment->next)
|
2008-04-29 13:23:06 +02:00
|
|
|
{
|
2008-04-19 11:40:19 +02:00
|
|
|
if (offset >= n && offset < n + segment->length)
|
|
|
|
return segment->address + offset - n;
|
|
|
|
n += segment->length;
|
2008-04-29 13:23:06 +02:00
|
|
|
}
|
2008-04-19 11:40:19 +02:00
|
|
|
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2005-05-28 00:45:31 +02:00
|
|
|
void Stream::putSegment(Stream * stream)
|
|
|
|
{
|
|
|
|
/***
|
|
|
|
for (Segment *segment = stream->segments; segment; segment = segment->next)
|
|
|
|
putSegment (segment->length, segment->address, true);
|
|
|
|
***/
|
|
|
|
|
|
|
|
if (stream->totalLength == 0)
|
|
|
|
return;
|
|
|
|
|
2008-04-20 12:40:58 +02:00
|
|
|
StreamSegment seg(stream);
|
2005-05-28 00:45:31 +02:00
|
|
|
|
|
|
|
if (current)
|
2008-04-29 13:23:06 +02:00
|
|
|
{
|
2005-05-28 00:45:31 +02:00
|
|
|
for (int len = currentLength - current->length; len && seg.available;)
|
2008-04-29 13:23:06 +02:00
|
|
|
{
|
2008-04-19 11:40:19 +02:00
|
|
|
const int l = MIN (len, seg.available);
|
2005-05-28 00:45:31 +02:00
|
|
|
putSegment (l, seg.data, true);
|
|
|
|
seg.advance (l);
|
|
|
|
len -= l;
|
2008-04-29 13:23:06 +02:00
|
|
|
}
|
|
|
|
}
|
2005-05-28 00:45:31 +02:00
|
|
|
|
|
|
|
if (seg.remaining)
|
|
|
|
seg.copy (alloc (seg.remaining), seg.remaining);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
2008-04-29 13:23:06 +02:00
|
|
|
Firebird::string Stream::getFBString() const
|
2005-05-28 00:45:31 +02:00
|
|
|
{
|
2008-04-24 17:49:43 +02:00
|
|
|
Firebird::string string;
|
2005-05-28 00:45:31 +02:00
|
|
|
char *p = string.getBuffer (totalLength);
|
|
|
|
|
2008-04-29 13:23:06 +02:00
|
|
|
for (const Segment *segment = segments; segment; segment = segment->next)
|
|
|
|
{
|
2005-05-28 00:45:31 +02:00
|
|
|
memcpy (p, segment->address, segment->length);
|
|
|
|
p += segment->length;
|
2008-04-29 13:23:06 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
fb_assert(p - string.begin() == totalLength);
|
2005-05-28 00:45:31 +02:00
|
|
|
|
|
|
|
return string;
|
|
|
|
}
|
|
|
|
|
|
|
|
char* Stream::alloc(int length)
|
|
|
|
{
|
|
|
|
totalLength += length;
|
|
|
|
|
|
|
|
if (!current || length > currentLength - current->length)
|
|
|
|
allocSegment (length);
|
|
|
|
|
2008-04-20 12:40:58 +02:00
|
|
|
char* const p = current->tail + current->length;
|
2005-05-28 00:45:31 +02:00
|
|
|
current->length += length;
|
|
|
|
|
|
|
|
return p;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void Stream::format(const char *pattern, ...)
|
|
|
|
{
|
2008-04-24 17:49:43 +02:00
|
|
|
Firebird::string temp;
|
|
|
|
|
2005-05-28 00:45:31 +02:00
|
|
|
va_list args;
|
|
|
|
va_start (args, pattern);
|
2008-04-24 17:49:43 +02:00
|
|
|
temp.vprintf(pattern, args);
|
2005-06-06 10:30:03 +02:00
|
|
|
va_end(args);
|
2008-04-24 17:49:43 +02:00
|
|
|
|
|
|
|
putSegment (temp.c_str());
|
2005-05-28 00:45:31 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
void Stream::truncate(int length)
|
|
|
|
{
|
|
|
|
int n = 0;
|
|
|
|
|
|
|
|
for (Segment *segment = segments; segment; segment = segment->next)
|
2008-04-29 13:23:06 +02:00
|
|
|
{
|
2005-05-28 00:45:31 +02:00
|
|
|
if (length >= n && length < n + segment->length)
|
2008-04-29 13:23:06 +02:00
|
|
|
{
|
2005-05-28 00:45:31 +02:00
|
|
|
current = segment;
|
|
|
|
current->length = length - n;
|
|
|
|
totalLength = length;
|
|
|
|
while (segment = current->next)
|
2008-04-29 13:23:06 +02:00
|
|
|
{
|
2005-05-28 00:45:31 +02:00
|
|
|
current->next = segment->next;
|
2008-04-29 13:23:06 +02:00
|
|
|
delete[] (char*) segment; // Was deallocation bug
|
2005-05-28 00:45:31 +02:00
|
|
|
}
|
2008-04-29 13:23:06 +02:00
|
|
|
return;
|
2005-05-28 00:45:31 +02:00
|
|
|
}
|
2008-04-29 13:23:06 +02:00
|
|
|
n += segment->length;
|
|
|
|
}
|
2005-05-28 00:45:31 +02:00
|
|
|
|
|
|
|
}
|
|
|
|
|
2008-04-19 11:40:19 +02:00
|
|
|
int Stream::compare(const Stream *stream) const
|
2005-05-28 00:45:31 +02:00
|
|
|
{
|
|
|
|
for (int offset = 0;;)
|
2008-04-29 13:23:06 +02:00
|
|
|
{
|
2008-04-20 12:40:58 +02:00
|
|
|
const int length1 = getSegmentLength(offset);
|
|
|
|
const int length2 = stream->getSegmentLength(offset);
|
2005-05-28 00:45:31 +02:00
|
|
|
if (length1 == 0)
|
2008-04-19 11:40:19 +02:00
|
|
|
{
|
2005-05-28 00:45:31 +02:00
|
|
|
if (length2)
|
|
|
|
return -1;
|
2008-04-19 11:40:19 +02:00
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
2005-05-28 00:45:31 +02:00
|
|
|
if (length2 == 0)
|
2008-04-29 13:23:06 +02:00
|
|
|
return 1;
|
2008-04-19 11:40:19 +02:00
|
|
|
const int length = MIN (length1, length2);
|
2005-05-28 00:45:31 +02:00
|
|
|
const char *p1 = (const char*) getSegment (offset);
|
|
|
|
const char *p2 = (const char*) stream->getSegment (offset);
|
|
|
|
for (const char *end = p1 + length; p1 < end;)
|
2008-04-29 13:23:06 +02:00
|
|
|
{
|
2005-05-28 00:45:31 +02:00
|
|
|
int n = *p1++ - *p2++;
|
|
|
|
if (n)
|
|
|
|
return n;
|
|
|
|
}
|
2008-04-29 13:23:06 +02:00
|
|
|
offset += length;
|
|
|
|
}
|
2005-05-28 00:45:31 +02:00
|
|
|
}
|