/*
   * 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 the usual suspects */
#include <stdio.h>
#include  <string.h>
#include  <errno.h>
#include <stdlib.h>
#include  <io.h>
#include  <ctype.h>
#include  <ibase.h>

/* special header file for shared library */

#include "my_filter.h"

/* routines in the filter */

static int blob_to_file (ISC_BLOB_CTL);
static int caller (short, ISC_BLOB_CTL,short, char*,  short*);
static int make_file (ISC_BLOB_CTL);
static int read_file (ISC_BLOB_CTL);
static void set_statistics (ISC_BLOB_CTL);
static int unzip (ISC_BLOB_CTL);
static int unzip_blob (ISC_BLOB_CTL);
static int write_file (ISC_BLOB_CTL);
static int zip (ISC_BLOB_CTL);
static int zip_file (ISC_BLOB_CTL);

/* These should probably be in ibase.h */

#define ACTION_open    0
#define ACTION_get_segment    1
#define ACTION_close    2
#define ACTION_create    3
#define ACTION_put_segment    4
#define ACTION_alloc    5
#define ACTION_free    6
#define ACTION_seek    7

/* the simple return codes */

#define SUCCESS            0
#define FAILURE            1

/* the two blob subtypes translated by this filter */

#define ZIPPED            -2
#define UNZIPPED            1

/* random value */

static int width = 40;

int unzip_filter ( short action,
                   ISC_BLOB_CTL control)
{
   /**************************************
   *
   *    u n z i p _  f i l t e r
   *
   **************************************
   *
   * Functional description
   *    read a  zipped blob and translate
   *      it to an unzipped blob.  Since this
   *      particular version of zip just inverts
   *      the blob, both sides are the same.
   *
   **************************************/
   return zip_filter (action, control);
}


int zip_filter ( short action,
                 ISC_BLOB_CTL control)
{
   /**************************************
   *
   *    z i p _  f i l t e r
   *
   **************************************
   *
   * Functional description
   *    zip a blob and store it.  In this
   *      case "zip" just means invert.  Most
   *      blob filters start out with a switch
   *      statement like this.
   *
   **************************************/
   int    status;

   switch (action)
   {

      /* open is called on an existing blob, so we create
      a temporary file and unzip the blob contents into it */

      case ACTION_open:
      status = make_file (control);

      if (!status)
      status = unzip_blob (control);
   break;

      /* create is called to make a new blob getting data
   from the user.  Create a temporary file and wait
   for input. */

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

      /* get segment is called after an open when the user
         wants data.  The blob has already been unzipped into
   a file, so we'll read back sections of the file */

      case ACTION_get_segment:
      status = read_file (control);
      break;

         /* close is called after both reading and creating a
            blob.  In the read case, we just need to get rid
   of the temporary file.  In the write case, we've got
   the data in a file in the form the user sent it.
   We need to zip it and pump it into the database. */

   case ACTION_close:
      if (control->ctl_to_sub_type == ZIPPED)
         status = zip_file (control);

      if ((FILE *)control->ctl_data[0])
         status = fclose ((FILE *)control->ctl_data[0]);

      if (!status && (char *)control->ctl_data[0])
         {
            status = unlink ((char *)control->ctl_data[4]);
            if (!status)
            free ((char *)control->ctl_data[4]);
         }

         break;

         /* put segment is called when the user has created a
            blob and wants to stuff data into it.  We hold the
      data in the temporary file that we made during the
      create call */

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

            }

   return status;
   }

static int blob_to_file (ISC_BLOB_CTL control)
{
   /**************************************
   *
   *    b l o b _ t o _ f i l e
   *
   **************************************
   *
   * Functional description
   *    Dump a blob into the temp file.  Here
   *      we need to call back into the engine -
   *      or whoever it was who called us - and
   *      ask for the segments of the blob.  We
   *      set up our own buffer and call to caller.
   *
   **************************************/
   FILE           *temp_file;
   short       length;
   char           buffer [1024], *p;
   int           status, c = 'n';

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

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


static int caller ( short action,
                    ISC_BLOB_CTL control,
                    short buffer_length,
                    char *buffer,
                    short *return_length)
{
   /**************************************
   *
   *        c a l l e r
   *
   **************************************
   *
   * Functional description
   *        Call next source filter.  This
   *        is an essential service routine for
   *        all blob filters.  The blob control
   *     block passed in to the filter includes
   *        both the handle of the caller's blob
   *        control block and the address of a
   *        routine to call to re-invoke the caller.
   *
   **************************************/
   int              status;
   ISC_BLOB_CTL        source;

   source = control->ctl_source_handle;
   source->ctl_status = control->ctl_status;
   source->ctl_buffer = buffer;
   source->ctl_buffer_length = buffer_length;

   status = (*source->ctl_source) (action, source);

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

   return status;
}

static int file_to_blob (ISC_BLOB_CTL control)
{
   /**************************************
   *
   *        f i l e _ t o _ b l o b
   *
   **************************************
   *
   * Functional description
   *        Copy a file to a blob, including
   *      the last little bit.  Since we
   *      just finished writing the file,
   *         rewind before start.
   *
   **************************************/
   FILE *  temp_file;
   short       length;
   char           buffer [1024], *p, c;
   int           status;

   memset (buffer, 0, sizeof(buffer));
   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 (ACTION_put_segment, control,
                       sizeof (buffer) - 1, buffer, &length);
      p = buffer;
   }
      }

   status = caller (ACTION_put_segment, control,
                    (short) (p - buffer), buffer, &length);
   fclose (temp_file);
   unlink ((char *)control->ctl_data[4]);
   free ((char *)control->ctl_data[4]);

   return SUCCESS;
}




static int make_file (ISC_BLOB_CTL control)
{
   /**************************************
   *
   *    m a k e _ f i l e
   *
   **************************************
   *
   * Functional description
   *    create a temp file and store the handle
   *    and a pointer to the file name in ctl_data
   *
   **************************************/
   FILE           *temp_file;
   char           *temp = "awhXXXXX", *file_name, *result;

   file_name = malloc (50);
   strncpy (file_name, temp, 50);

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

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

   control->ctl_data[0] = (long) temp_file;
   control->ctl_data[4] = (long) file_name;

   return SUCCESS;


   }

static int read_file (ISC_BLOB_CTL control)
{
   /**************************************
   *
   *    r e a d _ f i l e
   *
   **************************************
   *
   * Functional description
   *    Reads a file one line at a time
   *    and puts the data out as if it
   *    were coming from a blob.
   *
   **************************************/
   char    *p;
   FILE    *temp_file;
   short    length;
   int    c;

   if (control->ctl_to_sub_type != UNZIPPED)
   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 == 'n')  || p >= control->ctl_buffer + length)
      {
         control->ctl_segment_length = p - control->ctl_buffer;
      return (c == 'n') ? SUCCESS: isc_segment;
      }
         }

   return isc_segstr_eof;
}

static void set_statistics (ISC_BLOB_CTL control)
{
   /*************************************
   *
   *    s e t _ s t a t i s t i c s
   *
   *************************************
   *
   * Functional description
   *    Sets up the statistical fields
   *    in the passed in ctl structure.
   *    These fields are:
   *      ctl_max_segment - length of
   *         longest seg in blob (in
                                  *         bytes)
   *      ctl_number_segments - # of
   *         segments in blob
   *      ctl_total_length - total length
   *         of blob in bytes.
   *    we should reset the
   *    ctl structure, so that
   *    blob_info calls get the right
   *    values.
   *
   *************************************/
   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;

      length++;
      cur_length++;

      if (c == 'n')    /* that means we are at end of seg */
   {
      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 write_file (ISC_BLOB_CTL control)
{
   /**************************************
   *
   *    w r i t e _ f i l e
   *
   **************************************
   *
   * Functional description
   *
   *      takes user input and saves it in
   *      a temporary file.
   *
   **************************************/
   char       *p;
   FILE       *temp_file;
   short   length;


   if (control->ctl_to_sub_type != ZIPPED)
   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)
      {
         fputc (*p++, temp_file);
      }

   return SUCCESS;
}

static int unzip (ISC_BLOB_CTL control)
{
   /**************************************
   *
   *    u n z i p
   *
   **************************************
   *
   * Functional description
   *    in theory call unzip.  In fact
   *      read the blob and
   *
   **************************************/

   return zip (control);
}

static int unzip_blob (ISC_BLOB_CTL control)
{
   /**************************************
   *
   *    u n z i p _ b l o b
   *
   **************************************
   *
   * Functional description
   *    read a blob into a file.
   *
   **************************************/
   blob_to_file (control);
   return unzip (control);
}


static int zip (ISC_BLOB_CTL control)
{
   /**************************************
   *
   *    z i p
   *
   **************************************
   *
   * Functional description
   *    in theory call zip.  In fact
   *      just invert the file
   *
   **************************************/
   FILE           *in_file, *out_file;
   char           *buffer, *p, *in_file_name;
   int           c;

   set_statistics (control);
   in_file = (FILE *)control->ctl_data[0];
   in_file_name = (char *)control->ctl_data[4];
   rewind (in_file);
   c = fgetc (in_file);

   if (make_file (control))
   return FAILURE;

   out_file = (FILE *)control->ctl_data[0];
   buffer = malloc (control->ctl_total_length + 1);
   memset (buffer, 0, control->ctl_total_length + 1);

   p = buffer + (control->ctl_total_length);


   *(p) = 'n';

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

         if (p <= buffer)
      break;

         c = fgetc (in_file);
         }

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

   while (p < buffer + control->ctl_total_length)
      fputc ((int)*p++, out_file);

   fputc ('n', out_file);
   rewind (out_file);

   free (buffer);

   return SUCCESS;
}


static int zip_file (ISC_BLOB_CTL control)
{
   /**************************************
   *
   *    z i p  _ f i l e
   *
   **************************************
   *
   * Functional description
   *    invert a file and put it into a blob
   *
   **************************************/

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

   zip (control);

   file_to_blob (control);

   return SUCCESS;

}

Like this post? Share on: TwitterFacebookEmail


Related Articles


Author

IBPhoenix

Reading Time

~6 min read

Published

Category

Articles

Tags