Subject Re: [firebird-support] Blob External Filter
Author mangara@orbisindonesia.com
> Hopefully this would be useful...

oops, my mistake..
sorry!

/***************************************************
upper_lower_flt.h
***************************************************/
/*
declare filter uptolow input_type -101 output_type -100
entry_point 'uptolow_filter'
module_name '/usr/lib/firebird/UDF/libuplow.so.0';
declare filter lowtoup input_type -100 output_type -101
entry_point 'lowtoup_filter'
module_name '/usr/lib/firebird/UDF/libuplow.so.0';
*/

#ifndef __UPLOW_FILTER_H__
#define __UPLOW_FILTER_H__

#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <stdlib.h>
#include <unistd.h>
#include <ctype.h>
#include <ibase.h>

#define SUCCESS 0
#define FAILURE 1
#define UPPER -101
#define LOWER -100

char* u2l(char* buffer);
char* l2u(char* buffer);

ISC_STATUS uptolow_filter(short action,ISC_BLOB_CTL control);
ISC_STATUS lowtoup_filter(short action,ISC_BLOB_CTL control);

static int caller(short action,ISC_BLOB_CTL control,
short buffer_length,char *buffer,short *return_length);
static int make_file(ISC_BLOB_CTL control);
static void set_statistics (ISC_BLOB_CTL control,char eos);

static int blob_to_file(ISC_BLOB_CTL control,char eos);
static int file_to_blob(ISC_BLOB_CTL control);

static int read_file(ISC_BLOB_CTL control,char eos);
static int write_file(ISC_BLOB_CTL control);

static int transform(ISC_BLOB_CTL control,char eos);
static int transform_file(ISC_BLOB_CTL control,char eos);
static int transform_blob(ISC_BLOB_CTL control, char eos);

#endif //__UPLOW_FILTER_H__


/***************************************************
upper_lower_flt.c
***************************************************/
#include "upper_lower_flt.h"

ISC_STATUS uptolow_filter(short action,ISC_BLOB_CTL control)
{
return lowtoup_filter(action, control);
}

ISC_STATUS lowtoup_filter(short action,ISC_BLOB_CTL control)
{
int status;
FILE* fHan2cl;
char fNam2cl[32];

char eos = '9'; //end of segment marker

switch (action)
{
case isc_blob_filter_open:
status = make_file (control);
if (!status)
status = transform_blob(control,eos);
break;

case isc_blob_filter_get_segment:
status = read_file(control,eos);
break;

case isc_blob_filter_create:
status = (make_file(control));
break;

case isc_blob_filter_put_segment:
status = write_file(control);
break;

case isc_blob_filter_close:
if (control->ctl_to_sub_type == UPPER)
status = transform_file (control,eos);


memcpy(fNam2cl,(char*)&control->ctl_data[4],strlen((char*)&control->ctl_data[4]));
if (!status && (char *)control->ctl_data[0])
status = unlink (fNam2cl);
break;
}
return status;
}

static int caller(short action,ISC_BLOB_CTL control,
short buffer_length,char *buffer,short *return_length)
{
int status;
ISC_BLOB_CTL source;

source = control->ctl_source_handle;
source->ctl_status = control->ctl_status;
source->ctl_buffer = (unsigned char*)buffer;
source->ctl_buffer_length = (unsigned short)buffer_length;
status = (*source->ctl_source)(action, source);

if (return_length)
{
*return_length = source->ctl_segment_length;
}

return status;
}

static int make_file (ISC_BLOB_CTL control)
{
FILE *temp_file;
char *temp = "/tmp/ulf__XXXXXX", *file_name, *result;

file_name = (char*)malloc (32);
strncpy (file_name, temp, strlen(temp)+1);

if (!(result = mktemp (file_name)))
return FAILURE;

if (!(temp_file = fopen (file_name, "w+b")))
return FAILURE;

memset(control->ctl_data,0,8*sizeof(long));
control->ctl_data[0] = (long) temp_file;
memcpy(&control->ctl_data[4],file_name,strlen(file_name)+1);

free(file_name);
return SUCCESS;
}

static void set_statistics (ISC_BLOB_CTL control,char eos)
{
int max_seg_length = 0;
int length = 0;
int num_segs = 0;
int cur_length = 0;
FILE *temp_file;
char c;

temp_file = (FILE *)(control->ctl_data[0]);
rewind (temp_file);

for (;;)
{
c = fgetc (temp_file);

if (feof (temp_file))
break;
if (c!=eos)
{
length++;
cur_length++;
}

if (c == eos)
{
if (cur_length > max_seg_length)
max_seg_length = cur_length;
num_segs++;
cur_length = 0;
}
}

control->ctl_max_segment = max_seg_length;
control->ctl_number_segments = num_segs;
control->ctl_total_length = length;
}

static int blob_to_file(ISC_BLOB_CTL control,char eos)
{
FILE *temp_file;
short length;
char buffer [1024],*p;
int status;
int c = (int)eos;

temp_file = (FILE *)control->ctl_data[0];

while (!(status = caller (isc_blob_filter_get_segment, control,
sizeof (buffer) - 1, buffer, &length)) || status == isc_segment)
{
for (p = buffer; p < buffer + length; p++)
fputc (*p, temp_file);
}

return SUCCESS;
}

static int file_to_blob(ISC_BLOB_CTL control)
{
FILE *temp_file;
short length;
char buffer[1024],*p,c;
int status;
char fileName[32];


memcpy(fileName,&control->ctl_data[4],strlen((char*)&control->ctl_data[4])+1);
memset (buffer, 0, 1024);

temp_file = (FILE *)control->ctl_data[0];
rewind (temp_file);

p = buffer;

for (;;)
{
c = fgetc (temp_file);
if (feof (temp_file))
break;

*p++ = c;

if (p > buffer + control->ctl_buffer_length)
{
status = caller
(isc_blob_filter_put_segment,control,strlen(buffer),buffer,&length);
p = buffer;
}
}
fclose (temp_file);
unlink (fileName);

return SUCCESS;
}

static int read_file (ISC_BLOB_CTL control,char eos)
{
unsigned char *p;
FILE *temp_file;
short length;
int c;
int status;

if (control->ctl_to_sub_type != LOWER)
{
return isc_uns_ext;
}

p = control->ctl_buffer;
length = control->ctl_buffer_length;
temp_file = (FILE *)control->ctl_data [0];

for (;;)
{
c = fgetc (temp_file);
if (feof (temp_file))
{
break;
}

*p++ = c;

if ((c == (int)eos) || p >= control->ctl_buffer + length)
{
control->ctl_segment_length = p - control->ctl_buffer;
status = (c == (int)eos) ? SUCCESS: isc_segment;

return status;
}
}
return isc_segstr_eof;
}

static int write_file(ISC_BLOB_CTL control)
{
unsigned char *p;
FILE *temp_file;
short length;
unsigned char tmp;

if (control->ctl_to_sub_type != UPPER)
return isc_uns_ext;

p = control->ctl_buffer;
length = control->ctl_buffer_length;
temp_file = (FILE *)control->ctl_data[0];

while (p < control->ctl_buffer + length)
{
tmp = *p++;
fputc (tmp, temp_file);
}

return SUCCESS;
}

static int transform(ISC_BLOB_CTL control,char eos)
{
FILE *in_file, *out_file;
char *buffer, *p, *in_file_name;
int c;
int pp;
int status;

set_statistics (control,eos);

in_file = (FILE *)control->ctl_data[0];
in_file_name = (char*) malloc(32*sizeof(char));

memcpy(in_file_name,&control->ctl_data[4],strlen((char*)&control->ctl_data[4])+1);

rewind (in_file);

if (make_file (control))
return FAILURE;

out_file = (FILE *)control->ctl_data[0];

buffer = (char*)malloc (control->ctl_total_length + 1);
memset(buffer, 0, control->ctl_total_length + 1);

c = fgetc (in_file);
p = buffer;

while (!feof (in_file))
{
*p++ = (char)c;

if(p>=buffer + control->ctl_total_length)
break;

c = fgetc (in_file);
}

fclose(in_file);
unlink(in_file_name);
free (in_file_name);

switch(control->ctl_from_sub_type)
{
case UPPER:
if(control->ctl_to_sub_type != LOWER)
{
status = isc_uns_ext;
return status;
}
buffer = u2l(buffer);
break;

case LOWER:
if(control->ctl_to_sub_type != UPPER)
{
status = isc_uns_ext;
return status;
}
buffer = l2u(buffer);
break;

default:
status = isc_uns_ext;
return status;
}

p = buffer;
while (p < buffer + control->ctl_total_length)
{
pp = (int)*p++;
fputc (pp, out_file);
}
fputc (eos, out_file);
rewind (out_file);

free (buffer);
return SUCCESS;
}

static int transform_file (ISC_BLOB_CTL control,char eos)
{
if (control->ctl_to_sub_type != UPPER)
return isc_uns_ext;

transform(control,eos);
file_to_blob (control);

return SUCCESS;
}

static int transform_blob(ISC_BLOB_CTL control, char eos)
{
int status = blob_to_file (control,eos);

return transform(control,eos);
}

char* u2l(char* buffer)
{
int len = strlen(buffer);
char *tmp = (char*)malloc(len+1);
int a;

for(a=0; a<len; a++)
tmp[a] = (char)tolower((int)buffer[a]);

memcpy(buffer,tmp,len+1);
free(tmp);

return buffer;
}

char* l2u(char* buffer)
{
int len = strlen(buffer);
char *tmp = (char*)malloc(len+1);
int a;

for(a=0; a<len; a++)
tmp[a] = (char)toupper((int)buffer[a]);

memcpy(buffer,tmp,len+1);
free(tmp);

return buffer;
}