/***************************************************************************
 ** 
 **  File: readbin.c
 **
 **  Description: Routines for reading binary files.
 **
 **  Date: 8th January 2004
 **
 ***************************************************************************
 ***************************************************************************
 *
 *    Copyright (C) 2004 Scott A. Belmonte
 *    All rights reserved.
 *
 *    Redistribution and use in source and binary forms, with or without 
 *    modification, are permitted provided that the following conditions
 *    are met:
 *
 *    Redistributions of source code must retain the above copyright notice,
 *    this list of conditions and the following disclaimer.
 *
 *    Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 *
 *    Neither the name of the copyright holder nor the names of any
 *    contributors may be used to endorse or promote products derived from
 *    this software without specific prior written permission.
 * 
 *    THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 
 *    "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 
 *    LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 
 *    A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 
 *    OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 
 *    SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 
 *    LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 
 *    DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 
 *    THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 
 *    (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 
 *    OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 ***************************************************************************/

#include "readbin.h"

/****************************************************************************
 *
 * Function: read_bin_file
 *
 * Description: This function wraps the standard library function fread().
 *              It swaps the bytes of the raw data if the parameter swap
 *              is SWAP and size is either 2, 4 or 8. If size is not 2, 
 *              4 or 8 then the raw data are passed back unmodified.
 *
 * Input: buffer_p - Pointer the buffer where the data are to be stored.
 *        size     - The size in bytes of items to be read.
 *        count    - The number of items to read.
 *        stream_p - File handle of an open file.
 *        swap     - If SWAP then swap the bytes in the buffer,
 *                   If DONT_SWAP then don't swap bytes.
 *
 * Output: size_t - The actual number of items (not bytes) read. May be less
 *                  than the number requested if an error occurred while
 *                  reading the file or the end of file was reached.
 *
 ***************************************************************************/
size_t read_bin_file(void   *buffer_p,
                     size_t  size,
                     size_t  count,
                     FILE   *stream_p,
                     e_swap  swap)
{
    unsigned char *byte_p;
    unsigned char  tmp;
    size_t         num_items_read;
    size_t         i;

    num_items_read = 0;

    if (stream_p != NULL && buffer_p != NULL)
    {
        num_items_read = fread(buffer_p, size, count, stream_p);

        /* Swap bytes if asked to and if size is divisible by two. */ 
        if (swap == SWAP && (size % 2 == 0))
        {
            byte_p = (unsigned char *) buffer_p;
            switch (size)
            {
            case 2:
                for (i = 0; i < num_items_read; i++)          
                {
                    tmp           = *byte_p;
                    *byte_p       = *(byte_p + 1);
                    *(byte_p + 1) = tmp;
                    byte_p += size;
                }
                break;

            case 4:
                for (i = 0; i < num_items_read; i++)          
                {
                    tmp           = *byte_p;
                    *byte_p       = *(byte_p + 3);
                    *(byte_p + 3) = tmp;

                    tmp           = *(byte_p + 1);
                    *(byte_p + 1) = *(byte_p + 2);
                    *(byte_p + 2) = tmp;
                    byte_p += size;
                }
                break;

            case 8:
                for (i = 0; i < num_items_read; i++)          
                {
                    tmp           = *byte_p;
                    *byte_p       = *(byte_p + 7);
                    *(byte_p + 7) = tmp;

                    tmp           = *(byte_p + 1);
                    *(byte_p + 1) = *(byte_p + 6);
                    *(byte_p + 6) = tmp;

                    tmp           = *(byte_p + 2);
                    *(byte_p + 2) = *(byte_p + 5);
                    *(byte_p + 5) = tmp;

                    tmp           = *(byte_p + 3);
                    *(byte_p + 3) = *(byte_p + 4);
                    *(byte_p + 4) = tmp;
                    byte_p += size;
                }
                break;

            default:
                fprintf(stderr, "read_bin_file: Can't swap data. "); 
                fprintf(stderr, "Unsupported data size: %d\n", size);
                break;
            }
        }
    }

    return num_items_read;
}


/****************************************************************************
 *
 * Function: swap_2bytes
 *
 * Description: Swaps two bytes pointed to by raw_data_p.
 *
 * Input: raw_data_p   - Pointer to the bytes to swap.
 *
 * Output: None.
 *
 ***************************************************************************/
void swap_2bytes(void *raw_data_p)
{
    unsigned char *data_p = (unsigned char *) raw_data_p;
    unsigned char  tmp;

    tmp           = *data_p;
    *data_p       = *(data_p + 1);
    *(data_p + 1) = tmp;
}


/****************************************************************************
 *
 * Function: swap_4bytes
 *
 * Description: Swaps four bytes pointed to by raw_data_p.
 *
 * Input: raw_data_p   - Pointer to the bytes to swap.
 *
 * Output: None.
 *
 ***************************************************************************/
void swap_4bytes(void *raw_data_p)
{
    unsigned char *data_p = (unsigned char *) raw_data_p;
    unsigned char  tmp;

    /* Swap first and fourth bytes */
    tmp           = *data_p;
    *data_p       = *(data_p + 3);
    *(data_p + 3) = tmp;

    /* Swap second and third bytes */
    tmp           = *(data_p + 1);
    *(data_p + 1) = *(data_p + 2);
    *(data_p + 2) = tmp;
}


/**********************************************************************
 *    Function: get_endian
 *
 *    Description:
 *       Returns MACHINE_BIG_ENDIAN if the machine is big endian.
 *       Returns MACHINE_LITTLE_ENDIAN if the machine is little endian.
 *********************************************************************/
e_endian get_endian(void)
{
    unsigned char *ch;
    int i = 1;

    ch = (unsigned char *) &i;

    if (*ch != 1)
    {
        return MACHINE_BIG_ENDIAN;
    }
    else
    {
        return MACHINE_LITTLE_ENDIAN;
    }
}

