/* * LDASTools frameCPP - A library implementing the LIGO/Virgo frame
 * specification
 *
 * Copyright (C) 2018 California Institute of Technology
 *
 * LDASTools frameCPP is free software; you may redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 (GPLv2) of the
 * License or at your discretion, any later version.
 *
 * LDASTools frameCPP is distributed in the hope that it will be useful, but
 * without any warranty or even the implied warranty of merchantability
 * or fitness for a particular purpose. See the GNU General Public
 * License (GPLv2) for more details.
 *
 * Neither the names of the California Institute of Technology (Caltech),
 * The Massachusetts Institute of Technology (M.I.T), The Laser
 * Interferometer Gravitational-Wave Observatory (LIGO), nor the names
 * of its contributors may be used to endorse or promote products derived
 * from this software without specific prior written permission.
 *
 * You should have received a copy of the licensing terms for this
 * software included in the file LICENSE located in the top-level
 * directory of this package. If you did not, you can view a copy at
 * http://dcc.ligo.org/M1500244/LICENSE
 */

// Fix invalid `compress' flags in FrVect inside a frame file.

// MAKE BACKUP COPY OF YOUR DATA BEFORE RUNNING THIS PROGRAM!
// This is stright C code; compile with `gcc fixvect.c' command;
// aivanov@ligo.caltech.edu
// Mon Mar 27 17:12:21 PST 2000

#include <framecpp_config.h>

#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>

unsigned int
swap_int( unsigned int i )
{
    return ( i & 0xff ) << 24 | ( i & 0xff00 ) << 8 | ( i & 0xff0000 ) >> 8 |
        ( i & 0xff000000 ) >> 24;
}

unsigned short
swap_short( unsigned short i )
{
    return ( i & 0xff ) << 8 | ( i & 0xff00 ) >> 8;
}

#define SWAP_INT( i ) ( swap ? swap_int( i ) : i )
#define SWAP_SHORT( i ) ( swap ? swap_short( i ) : i )

main( int argc, char* argv[] )
{
    int            fd, swap;
    unsigned char  fh[ 40 ];
    unsigned short vect_id, frameh_id;
    int            nstructs;
    int            nproc = 0;
    int            ninvalid = 0;
    int            nframes = 0;

    if ( argc < 2 )
    {
        fprintf( stderr,
                 "Purpose: fix invalid `Compress' attribute of FrVect "
                 "structure in a frame file\n" );
        fprintf( stderr, "Usage: %s <single frame file to fix>\n", argv[ 0 ] );
        return 1;
    }
    fd = open( argv[ 1 ], O_RDWR );
    if ( fd < 0 )
    {
        fprintf( stderr, "Can't open `%s' to read and write\n", argv[ 1 ] );
        return 1;
    }
    // skip file header
    read( fd, fh, 40 );
    {
        unsigned short s = 0x1234;
        swap = ( *(short*)( fh + 12 ) != s );
    }

    vect_id = 0;
    frameh_id = 0;

    for ( nstructs = 0;; nstructs++ )
    {
        unsigned int length;
        unsigned short class;

        int nread = read( fd, &length, sizeof( length ) );
        if ( nread != sizeof( length ) )
        {
            printf( "Read %d frames in `%s'\n", nframes, argv[ 1 ] );
            printf( "Read %d structures and found %d vectors; %d were invalid "
                    "and fixed\n",
                    nstructs,
                    nproc,
                    ninvalid );
            break;
        }
        length = SWAP_INT( length );
        read( fd, &class, sizeof( class ) );
        class = SWAP_SHORT( class );
        //    printf("%d\t%d\n", length, class);
        if ( !length )
        {
            fprintf( stderr,
                     "File parse error -- structure length was zero\n" );
            exit( 1 );
        }

        length -= sizeof( length );
        length -= sizeof( class );

        switch ( class )
        {
        case 1: // SH
        {
            unsigned short len, id;
            char           name[ 1024 ];
            // read class instance, name and IF
            read( fd, &len, sizeof( len ) ); // short instance
            read( fd, &len, sizeof( len ) ); // short name length
            len = SWAP_SHORT( len );
            read( fd, &name, len ); // short name length
            read( fd, &id, sizeof( id ) ); // short class Id
            id = SWAP_SHORT( id );

            length -= 3 * sizeof( short ) + len;

            if ( !strcasecmp( name, "frameh" ) )
            {
                frameh_id = id;
                printf( "FrameH class ID is %d\n", id );
            }
            else if ( !strcasecmp( name, "frvect" ) )
            {
                vect_id = id;
                printf( "FrVect class ID is %d\n", id );
            }
        }
        break;
        case 2: // SE
            break;
        }
        if ( class == frameh_id )
            nframes++;
        else if ( class == vect_id )
        {
            unsigned short len, compress;
            char           name[ 1024 ];

            nproc++;
            // get vector name
            read( fd, &len, sizeof( len ) ); // short instance
            read( fd, &len, sizeof( len ) ); // short name length
            len = SWAP_SHORT( len );
            read( fd, &name, len ); // short name length
            read( fd, &compress, sizeof( compress ) ); // short compress flag
            compress = SWAP_SHORT( compress );
            //      printf("Vector Compress %d\n", compress);

            length -= sizeof( len ) * 2 + len + sizeof( compress );

            // Fix compression flag
            //
            if ( compress == 0x0300 )
            {
                unsigned short a = SWAP_SHORT( 3 );
                lseek( fd, -2, SEEK_CUR );
                write( fd, &a, sizeof( a ) );
                ninvalid++;
            }
        }
        lseek( fd, length, SEEK_CUR );
    }
    return 0;
}
