2007-02-13 21:51:18 +00:00
|
|
|
/***************************************************************************
|
|
|
|
* __________ __ ___.
|
|
|
|
* Open \______ \ ____ ____ | | _\_ |__ _______ ___
|
|
|
|
* Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
|
|
|
|
* Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
|
|
|
|
* Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
|
|
|
|
* \/ \/ \/ \/ \/
|
|
|
|
* $Id$
|
|
|
|
*
|
|
|
|
* Copyright (C) 2007 by Miika Pekkarinen
|
|
|
|
*
|
2008-06-28 18:10:04 +00:00
|
|
|
* This program is free software; you can 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
|
|
|
|
* of the License, or (at your option) any later version.
|
2007-02-13 21:51:18 +00:00
|
|
|
*
|
|
|
|
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
|
|
|
|
* KIND, either express or implied.
|
|
|
|
*
|
|
|
|
****************************************************************************/
|
|
|
|
|
2007-02-14 19:20:13 +00:00
|
|
|
#include <ctype.h>
|
2007-02-13 21:51:18 +00:00
|
|
|
#include <string.h>
|
2007-02-14 07:46:11 +00:00
|
|
|
#include <inttypes.h>
|
2007-02-13 21:51:18 +00:00
|
|
|
#include "structec.h"
|
|
|
|
#include "system.h"
|
|
|
|
#include "file.h"
|
|
|
|
|
|
|
|
#define MAX_STRUCT_SIZE 128
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Convert the struct endianess with the instructions provided.
|
2015-02-24 21:21:59 +00:00
|
|
|
*
|
2007-02-13 21:51:18 +00:00
|
|
|
* For example:
|
|
|
|
* struct test {
|
|
|
|
* long par1;
|
|
|
|
* short par2;
|
|
|
|
* short par3;
|
|
|
|
* };
|
2015-02-24 21:21:59 +00:00
|
|
|
*
|
2007-02-13 21:51:18 +00:00
|
|
|
* structec_convert(instance_of_test, "lss", sizeof(struct test), true);
|
2015-02-24 21:21:59 +00:00
|
|
|
*
|
2007-02-13 21:51:18 +00:00
|
|
|
* Structures to be converted must be properly padded.
|
2015-02-24 21:21:59 +00:00
|
|
|
*
|
2007-02-13 21:51:18 +00:00
|
|
|
* @param structure Pointer to the struct being converted.
|
|
|
|
* @param ecinst Instructions how to do the endianess conversion.
|
|
|
|
* @param count Number of structures to write
|
|
|
|
* @param enable Conversion is not made unless this is true.
|
|
|
|
*/
|
2015-02-24 21:21:59 +00:00
|
|
|
void structec_convert(void *structure, const char *ecinst,
|
2007-02-13 21:51:18 +00:00
|
|
|
long count, bool enable)
|
|
|
|
{
|
|
|
|
const char *ecinst_ring = ecinst;
|
|
|
|
char *buf = (char *)structure;
|
2015-02-24 21:21:59 +00:00
|
|
|
|
2007-02-13 21:51:18 +00:00
|
|
|
if (!enable)
|
|
|
|
return;
|
2015-02-24 21:21:59 +00:00
|
|
|
|
2007-02-13 21:51:18 +00:00
|
|
|
while (count > 0)
|
|
|
|
{
|
|
|
|
switch (*ecinst_ring)
|
|
|
|
{
|
|
|
|
/* Swap nothing. */
|
|
|
|
case 'c':
|
|
|
|
{
|
|
|
|
buf++;
|
|
|
|
break;
|
|
|
|
}
|
2015-02-24 21:21:59 +00:00
|
|
|
|
2007-02-13 21:51:18 +00:00
|
|
|
/* Swap 2 bytes. */
|
|
|
|
case 's':
|
|
|
|
{
|
2007-02-14 07:46:11 +00:00
|
|
|
uint16_t *data = (uint16_t *)buf;
|
|
|
|
*data = swap16(*data);
|
2007-02-13 21:51:18 +00:00
|
|
|
buf += 2;
|
|
|
|
break;
|
|
|
|
}
|
2007-02-14 07:46:11 +00:00
|
|
|
|
2007-02-13 21:51:18 +00:00
|
|
|
/* Swap 4 bytes. */
|
|
|
|
case 'l':
|
|
|
|
{
|
2007-02-14 07:46:11 +00:00
|
|
|
uint32_t *data = (uint32_t *)buf;
|
|
|
|
*data = swap32(*data);
|
2007-02-13 21:51:18 +00:00
|
|
|
buf += 4;
|
|
|
|
break;
|
|
|
|
}
|
2015-02-24 21:21:59 +00:00
|
|
|
|
2007-02-14 19:20:13 +00:00
|
|
|
/* Skip N bytes, idea taken from metadata.c */
|
2007-02-13 21:51:18 +00:00
|
|
|
default:
|
2007-02-14 19:20:13 +00:00
|
|
|
{
|
|
|
|
if (isdigit(*ecinst_ring))
|
|
|
|
buf += (*ecinst_ring - '0');
|
|
|
|
|
2007-02-13 21:51:18 +00:00
|
|
|
break;
|
2007-02-14 19:20:13 +00:00
|
|
|
}
|
2007-02-13 21:51:18 +00:00
|
|
|
}
|
2015-02-24 21:21:59 +00:00
|
|
|
|
2007-02-13 21:51:18 +00:00
|
|
|
ecinst_ring++;
|
|
|
|
if (*ecinst_ring == '\0')
|
|
|
|
{
|
|
|
|
ecinst_ring = ecinst;
|
|
|
|
count--;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Determines the size of a struct in bytes by using endianess correction
|
|
|
|
* string format.
|
2015-02-24 21:21:59 +00:00
|
|
|
*
|
2007-02-13 21:51:18 +00:00
|
|
|
* @param ecinst endianess correction string.
|
|
|
|
* @return length of the struct in bytes.
|
|
|
|
*/
|
2008-05-03 08:35:14 +00:00
|
|
|
static size_t structec_size(const char *ecinst)
|
2007-02-13 21:51:18 +00:00
|
|
|
{
|
|
|
|
size_t size = 0;
|
2015-02-24 21:21:59 +00:00
|
|
|
|
2007-02-13 21:51:18 +00:00
|
|
|
do
|
|
|
|
{
|
|
|
|
switch (*ecinst)
|
|
|
|
{
|
|
|
|
case 'c': size += 1; break;
|
|
|
|
case 's': size += 2; break;
|
|
|
|
case 'l': size += 4; break;
|
2015-02-24 21:21:59 +00:00
|
|
|
default:
|
2007-02-14 19:20:13 +00:00
|
|
|
if (isdigit(*ecinst))
|
|
|
|
size += (*ecinst - '0');
|
2007-02-13 21:51:18 +00:00
|
|
|
}
|
|
|
|
} while (*(++ecinst) != '\0');
|
2015-02-24 21:21:59 +00:00
|
|
|
|
2007-02-13 21:51:18 +00:00
|
|
|
return size;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Reads endianess corrected structure members from the given file.
|
2015-02-24 21:21:59 +00:00
|
|
|
*
|
2007-02-13 21:51:18 +00:00
|
|
|
* @param fd file descriptor of the file being read.
|
|
|
|
* @param buf endianess corrected data is placed here.
|
|
|
|
* @param scount the number of struct members to read.
|
|
|
|
* @param ecinst endianess correction string.
|
|
|
|
* @param ec if true, endianess correction is enabled.
|
|
|
|
*/
|
|
|
|
ssize_t ecread(int fd, void *buf, size_t scount, const char *ecinst, bool ec)
|
|
|
|
{
|
|
|
|
ssize_t ret;
|
|
|
|
size_t member_size = structec_size(ecinst);
|
2015-02-24 21:21:59 +00:00
|
|
|
|
2007-02-13 21:51:18 +00:00
|
|
|
ret = read(fd, buf, scount * member_size);
|
|
|
|
structec_convert(buf, ecinst, scount, ec);
|
2015-02-24 21:21:59 +00:00
|
|
|
|
2007-02-13 21:51:18 +00:00
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Writes endianess corrected structure members to the given file.
|
2015-02-24 21:21:59 +00:00
|
|
|
*
|
2007-02-13 21:51:18 +00:00
|
|
|
* @param fd file descriptor of the file being written to.
|
|
|
|
* @param buf endianess corrected data is read here.
|
|
|
|
* @param scount the number of struct members to write.
|
|
|
|
* @param ecinst endianess correction string.
|
|
|
|
* @param ec if true, endianess correction is enabled.
|
|
|
|
*/
|
2015-02-24 21:21:59 +00:00
|
|
|
ssize_t ecwrite(int fd, const void *buf, size_t scount,
|
2007-02-13 21:51:18 +00:00
|
|
|
const char *ecinst, bool ec)
|
|
|
|
{
|
|
|
|
char tmp[MAX_STRUCT_SIZE];
|
2015-02-24 21:23:17 +00:00
|
|
|
ssize_t member_size = structec_size(ecinst);
|
|
|
|
|
2007-02-13 21:51:18 +00:00
|
|
|
if (ec)
|
|
|
|
{
|
|
|
|
const char *p = (const char *)buf;
|
|
|
|
int maxamount = (int)(MAX_STRUCT_SIZE / member_size);
|
|
|
|
int i;
|
2015-02-24 21:21:59 +00:00
|
|
|
|
2007-02-13 21:51:18 +00:00
|
|
|
for (i = 0; i < (long)scount; i += maxamount)
|
|
|
|
{
|
|
|
|
long amount = MIN((int)scount-i, maxamount);
|
2015-02-24 21:21:59 +00:00
|
|
|
|
2007-02-13 21:51:18 +00:00
|
|
|
memcpy(tmp, p, member_size * amount);
|
|
|
|
structec_convert(tmp, ecinst, amount, true);
|
2015-02-24 21:23:17 +00:00
|
|
|
ssize_t ret = write(fd, tmp, amount * member_size);
|
|
|
|
|
|
|
|
if(ret != amount * member_size)
|
|
|
|
return ret;
|
|
|
|
|
2007-02-13 21:51:18 +00:00
|
|
|
p += member_size * amount;
|
|
|
|
}
|
2015-02-24 21:21:59 +00:00
|
|
|
|
2007-02-13 21:51:18 +00:00
|
|
|
return scount * member_size;
|
|
|
|
}
|
2015-02-24 21:21:59 +00:00
|
|
|
|
2007-02-13 21:51:18 +00:00
|
|
|
return write(fd, buf, scount * member_size);
|
|
|
|
}
|