Reading WAV file with possibly misaligned data - c

I am trying to read an audio wave file from a database of wave files. My code for reading the wave file looks like so
/**
* Read and parse a wave file
*
**/
#include <unistd.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include "wave.h"
#define TRUE 1
#define FALSE 0
// WAVE header structure
unsigned char buffer4[4];
unsigned char buffer2[2];
char* seconds_to_time(float seconds);
FILE *ptr;
char *filename;
struct HEADER header;
int main(int argc, char **argv) {
filename = (char*) malloc(sizeof(char) * 1024);
if (filename == NULL) {
printf("Error in malloc\n");
exit(1);
}
// get file path
char cwd[1024];
if (getcwd(cwd, sizeof(cwd)) != NULL) {
strcpy(filename, cwd);
// get filename from command line
if (argc < 2) {
printf("No wave file specified\n");
return;
}
strcat(filename, "/");
strcat(filename, argv[1]);
printf("%s\n", filename);
}
// open file
printf("Opening file..\n");
ptr = fopen(filename, "rb");
if (ptr == NULL) {
printf("Error opening file\n");
exit(1);
}
int read = 0;
// read header parts
read = fread(header.riff, sizeof(header.riff), 1, ptr);
printf("(1-4): %s \n", header.riff);
read = fread(buffer4, sizeof(buffer4), 1, ptr);
printf("%u %u %u %u\n", buffer4[0], buffer4[1], buffer4[2], buffer4[3]);
// convert little endian to big endian 4 byte int
header.overall_size = buffer4[0] |
(buffer4[1]<<8) |
(buffer4[2]<<16) |
(buffer4[3]<<24);
printf("(5-8) Overall size: bytes:%u, Kb:%u \n", header.overall_size, header.overall_size/1024);
read = fread(header.wave, sizeof(header.wave), 1, ptr);
printf("(9-12) Wave marker: %s\n", header.wave);
read = fread(header.fmt_chunk_marker, sizeof(header.fmt_chunk_marker), 1, ptr);
printf("(13-16) Fmt marker: %s\n", header.fmt_chunk_marker);
read = fread(buffer4, sizeof(buffer4), 1, ptr);
printf("%u %u %u %u\n", buffer4[0], buffer4[1], buffer4[2], buffer4[3]);
// convert little endian to big endian 4 byte integer
header.length_of_fmt = buffer4[0] |
(buffer4[1] << 8) |
(buffer4[2] << 16) |
(buffer4[3] << 24);
printf("(17-20) Length of Fmt header: %u \n", header.length_of_fmt);
read = fread(buffer2, sizeof(buffer2), 1, ptr); printf("%u %u \n", buffer2[0], buffer2[1]);
header.format_type = buffer2[0] | (buffer2[1] << 8);
char format_name[10] = "";
if (header.format_type == 1)
strcpy(format_name,"PCM");
else if (header.format_type == 6)
strcpy(format_name, "A-law");
else if (header.format_type == 7)
strcpy(format_name, "Mu-law");
printf("(21-22) Format type: %u %s \n", header.format_type, format_name);
read = fread(buffer2, sizeof(buffer2), 1, ptr);
printf("%u %u \n", buffer2[0], buffer2[1]);
header.channels = buffer2[0] | (buffer2[1] << 8);
printf("(23-24) Channels: %u \n", header.channels);
read = fread(buffer4, sizeof(buffer4), 1, ptr);
printf("%u %u %u %u\n", buffer4[0], buffer4[1], buffer4[2], buffer4[3]);
header.sample_rate = buffer4[0] |
(buffer4[1] << 8) |
(buffer4[2] << 16) |
(buffer4[3] << 24);
printf("(25-28) Sample rate: %u\n", header.sample_rate);
read = fread(buffer4, sizeof(buffer4), 1, ptr);
printf("%u %u %u %u\n", buffer4[0], buffer4[1], buffer4[2], buffer4[3]);
header.byterate = buffer4[0] |
(buffer4[1] << 8) |
(buffer4[2] << 16) |
(buffer4[3] << 24);
printf("(29-32) Byte Rate: %u , Bit Rate:%u\n", header.byterate, header.byterate*8);
read = fread(buffer2, sizeof(buffer2), 1, ptr);
printf("%u %u \n", buffer2[0], buffer2[1]);
header.block_align = buffer2[0] |
(buffer2[1] << 8);
printf("(33-34) Block Alignment: %u \n", header.block_align);
read = fread(buffer2, sizeof(buffer2), 1, ptr);
printf("%u %u \n", buffer2[0], buffer2[1]);
header.bits_per_sample = buffer2[0] |
(buffer2[1] << 8);
printf("(35-36) Bits per sample: %u \n", header.bits_per_sample);
read = fread(header.data_chunk_header, sizeof(header.data_chunk_header), 1, ptr);
printf("(37-40) Data Marker: %s \n", header.data_chunk_header);
read = fread(buffer4, sizeof(buffer4), 1, ptr);
printf("%u %u %u %u\n", buffer4[0], buffer4[1], buffer4[2], buffer4[3]);
header.data_size = buffer4[0] |
(buffer4[1] << 8) |
(buffer4[2] << 16) |
(buffer4[3] << 24 );
printf("(41-44) Size of data chunk: %u \n", header.data_size);
// calculate no.of samples
long num_samples = (8 * header.data_size) / (header.channels * header.bits_per_sample);
printf("Number of samples:%lu \n", num_samples);
long size_of_each_sample = (header.channels * header.bits_per_sample) / 8;
printf("Size of each sample:%ld bytes\n", size_of_each_sample);
// calculate duration of file
float duration_in_seconds = (float) header.overall_size / header.byterate;
printf("Approx.Duration in seconds=%f\n", duration_in_seconds);
printf("Approx.Duration in h:m:s=%s\n", seconds_to_time(duration_in_seconds));
// read each sample from data chunk if PCM
if (header.format_type == 1) { // PCM
printf("Dump sample data? Y/N?");
char c = 'n';
scanf("%c", &c);
if (c == 'Y' || c == 'y') {
long i =0;
char data_buffer[size_of_each_sample];
int size_is_correct = TRUE;
// make sure that the bytes-per-sample is completely divisible by num.of channels
long bytes_in_each_channel = (size_of_each_sample / header.channels);
if ((bytes_in_each_channel * header.channels) != size_of_each_sample) {
printf("Error: %ld x %ud <> %ld\n", bytes_in_each_channel, header.channels, size_of_each_sample);
size_is_correct = FALSE;
}
if (size_is_correct) {
// the valid amplitude range for values based on the bits per sample
long low_limit = 0l;
long high_limit = 0l;
switch (header.bits_per_sample) {
case 8:
low_limit = -128;
high_limit = 127;
break;
case 16:
low_limit = -32768;
high_limit = 32767;
break;
case 32:
low_limit = -2147483648;
high_limit = 2147483647;
break;
}
printf("\n\n.Valid range for data values : %ld to %ld \n", low_limit, high_limit);
for (i =1; i <= num_samples; i++) {
printf("==========Sample %ld / %ld=============\n", i, num_samples);
read = fread(data_buffer, sizeof(data_buffer), 1, ptr);
if (read == 1) {
// dump the data read
unsigned int xchannels = 0;
int data_in_channel = 0;
for (xchannels = 0; xchannels < header.channels; xchannels ++ ) {
printf("Channel#%d : ", (xchannels+1));
// convert data from little endian to big endian based on bytes in each channel sample
if (bytes_in_each_channel == 4) {
data_in_channel = data_buffer[0] |
(data_buffer[1]<<8) |
(data_buffer[2]<<16) |
(data_buffer[3]<<24);
}
else if (bytes_in_each_channel == 2) {
data_in_channel = data_buffer[0] |
(data_buffer[1] << 8);
}
else if (bytes_in_each_channel == 1) {
data_in_channel = data_buffer[0];
}
printf("%d ", data_in_channel);
// check if value was in range
if (data_in_channel < low_limit || data_in_channel > high_limit)
printf("**value out of range\n");
printf(" | ");
}
printf("\n");
}
else {
printf("Error reading file. %d bytes\n", read);
break;
}
} // for (i =1; i <= num_samples; i++) {
} // if (size_is_correct) {
} // if (c == 'Y' || c == 'y') {
} // if (header.format_type == 1) {
printf("Closing file..\n");
fclose(ptr);
// cleanup before quitting
free(filename);
return 0;
}
/**
* Convert seconds into hh:mm:ss format
* Params:
* seconds - seconds value
* Returns: hms - formatted string
**/
char* seconds_to_time(float raw_seconds) {
char *hms;
int hours, hours_residue, minutes, seconds, milliseconds;
hms = (char*) malloc(100);
sprintf(hms, "%f", raw_seconds);
hours = (int) raw_seconds/3600;
hours_residue = (int) raw_seconds % 3600;
minutes = hours_residue/60;
seconds = hours_residue % 60;
milliseconds = 0;
// get the decimal part of raw_seconds to get milliseconds
char *pos;
pos = strchr(hms, '.');
int ipos = (int) (pos - hms);
char decimalpart[15];
memset(decimalpart, ' ', sizeof(decimalpart));
strncpy(decimalpart, &hms[ipos+1], 3);
milliseconds = atoi(decimalpart);
sprintf(hms, "%d:%d:%d.%d", hours, minutes, seconds, milliseconds);
return hms;
}
the wave.h that is included looks like this
// WAVE file header format
struct HEADER {
unsigned char riff[4]; // RIFF string
unsigned int overall_size ; // overall size of file in bytes
unsigned char wave[4]; // WAVE string
unsigned char fmt_chunk_marker[4]; // fmt string with trailing null char
unsigned int length_of_fmt; // length of the format data
unsigned int format_type; // format type. 1-PCM, 3- IEEE float, 6 - 8bit A law, 7 - 8bit mu law
unsigned int channels; // no.of channels
unsigned int sample_rate; // sampling rate (blocks per second)
unsigned int byterate; // SampleRate * NumChannels * BitsPerSample/8
unsigned int block_align; // NumChannels * BitsPerSample/8
unsigned int bits_per_sample; // bits per sample, 8- 8bits, 16- 16 bits etc
unsigned char data_chunk_header [4]; // DATA string or FLLR string
unsigned int data_size; // NumSamples * NumChannels * BitsPerSample/8 - size of the next chunk that will be read
};
. I have tried with other wav files and seem to get the correct output (i.e. "RIFF" and "WAVE" from the header). However, with the one I care about this is the output
________________________________________________________________________________~/Downloads/libmfcc-master $: ./a.out audioclip-1523814201.wav
/home/sfelde2/Downloads/libmfcc-master/audioclip-1523814201.wav
Opening file..
(1-4):
102 116 121 112
(5-8) Overall size: bytes:1887007846, Kb:1842781
(9-12) Wave marker: isom
(13-16) Fmt marker:
105 115 111 109
(17-20) Length of Fmt header: 1836020585
105 115
(21-22) Format type: 29545
111 50
(23-24) Channels: 12911
109 112 52 49
(25-28) Sample rate: 825520237
0 0 0 8
(29-32) Byte Rate: 134217728 , Bit Rate:1073741824
102 114
(33-34) Block Alignment: 29286
101 101
(35-36) Bits per sample: 25957
(37-40) Data Marker:
109 100 97 116
(41-44) Size of data chunk: 1952539757
Number of samples:8
Size of each sample:41891353 bytes
Approx.Duration in seconds=14.059304
Approx.Duration in h:m:s=0:0:14.59
Closing file..
I have started to wonder if the wave field where it says "isom" might signify it is aligned differently but I haven't been able to find anything on ISOM. Thiiis along with the fact that it is not printing the RIFF string and spitting out the wrong values for the data makes me wonder if there is anyway I can figure out where the data starts. Any ideas on what could be the issue or if theres anyway I can debug this so that I can use the wav file would be greatly appreciated.

Related

Logic to set a bits of given number from first occurance of bits 1 as given example?

Logic to set a bits of given number (as show in example below) from first occurance of 1 next should must be 1 and then alternative 0 and 1 should continue till all bits field is filled up? example if num =10 then its binary is 0000 0000 0000 0000 0000 0000 0000 1010
out put should be 0000 0000 0000 0000 0000 0000 0000 1101
similar if it is 16 10000 then 0/p should be 11010 and if 15 ie 1111 then output 11010 when we get first bits as 1 in give number then next bits should be 1 and the alternative 0 and 1?my logic is below please help to fix it
int main()
{
int i,onetime=1,flag=1;
scanf("%d",&num);
for(i=31;i>=0;i++)
{
if(num & 1<<i)
break; // this will give first set bits of num ie 1
}
--i; // move to next adjacent bit and this should also be 1
for(;i>0;)
{
if(onetime=1) // here forcely making 1
{
num=num|1<<i;
onetime=0;
}
if(flag==1) // set to 0
{
num=num&~(1<<i)
flag=0;
}
if(flag==0) //set to 1
{
num=num|(1<<i);
flag =1-flag; //will keep on switch 0 and 1
}
}
}
While the logic behind doing what you want to do it fairly trivial, the implementation isn't. Ignoring the need to output a binary representation for the moment, the logic can be broken down to:
1.) finding the most significant bit (msb)
2.) toggling each bit beginning at (msb - 1) to 0 (subtracting 'x' from msb)
3.) setting each bit if (x % 2) == 0, clearing otherwise
The implementation isn't difficult, it is just rather involved (note: this is for 32-bit values only):
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <limits.h> /* for CHAR_BIT */
inline int getmsb (uint32_t x);
char *fmtbinstr_32 (uint32_t x, const size_t szgrp, char *sep);
/* set or clear bit n */
inline void bit_set (uint32_t *bf, int n) { *bf |= (1 << n); }
inline void bit_clear (uint32_t *bf, int n) { *bf &= ~(1 << n); }
int
main (int argc, char *argv[]) {
if (argc < 2 ) {
fprintf (stderr, "Error: insufficient input, usage: %s int\n", argv[0]);
return 1;
}
uint32_t number = (uint32_t)atoi (argv[1]);
uint32_t newnum = number;
int msb = getmsb (number);
int it = 0;
printf ("\n number: %s\n msb : %d\n\n", fmtbinstr_32 (number, 4, "-"), msb);
it = (int)msb;
for (it = 1; it <= msb; it++) {
if ((it % 2) == 0)
bit_clear (&newnum, msb - it);
else
bit_set (&newnum, msb - it);
}
printf (" newnum: %s\n\n", fmtbinstr_32 (newnum, 4, "-"));
return 0;
}
/* return the most significant bit MSB for the value supplied (bit scan reverse)
* for 32-bit values. For 64-bit values, use 'bsrq'.
*/
inline int getmsb (uint32_t x)
{
asm ("bsr %0, %0" : "=r" (x) : "0" (x));
return x;
}
/* binary string of uint32_t x, in szgrp bits groups, separated by sep */
char *fmtbinstr_32 (uint32_t x, const size_t szgrp, char *sep)
{
char b [sizeof(uint32_t) * CHAR_BIT + 1] = {0};
static char fmtb [sizeof (uint32_t) * 2 * CHAR_BIT] = {0};
const size_t len = sizeof(uint32_t) * CHAR_BIT + 1;
register size_t z = 0;
register size_t idx = 0;
if (szgrp > ((len - 1) / 2) || szgrp <= 0) {
fprintf (stderr, "%s() error: invalid input: szgrp '%d' out of range (%d >= szgrp > 0)\n", __func__, (int) szgrp, (int) ((len - 1) / 2));
return NULL; // could make b static and return b instead
}
for (z = 0; z < len - 1; z++)
b [sizeof (uint32_t) * CHAR_BIT - 1 - z] = ((x>>z) & 0x1) ? '1' : '0';
if (sep [0] == '\0') {
fprintf (stderr, "%s() error: invalid input: 'sep' is undefined or empty string\n", __func__);
return NULL;
}
for (z = 0; z < len - 1; z++) {
if ((len - 1 - z) % szgrp == 0 && z > 0) {
fmtb [idx] = sep [0];
idx++;
}
fmtb [idx] = b [z];
idx++;
}
fmtb [idx] = '\0';
return fmtb;
}
output:
$ ./bin/bitalt 10
number: 0000-0000-0000-0000-0000-0000-0000-1010
msb : 3
newnum: 0000-0000-0000-0000-0000-0000-0000-1101
$ ./bin/bitalt 55
number: 0000-0000-0000-0000-0000-0000-0011-0111
msb : 5
newnum: 0000-0000-0000-0000-0000-0000-0011-0101
Basic Version
This version employs the same logic, but leaves out the binary print function and the getmsb function that uses assembler instructions to get the most significant bit. This example uses most of the logic from the original question, but adjust the loops as needed:
#include <stdio.h>
int main (void) {
int i = 0, msb = 0;
unsigned int num = 0;
printf ("\nEnter a number: ");
scanf ("%u", &num);
for (i = 31; i >= 0; i--) {
if (num & 1 << i)
break; // this will give first set bits of num ie 1
} // which is the most significant bit (msb)
msb = i; // save msb
printf ("\n The most significant bit (msb): %d\n", msb);
// we want the index [msb - i] to step down from (msb-1) to 0
// e.g. if num=10, then msb=3, so we want the indexes to be 2,1,0
// so let i start at 1 and we will do (msb -i) until i=msb
for (i = 1; i <= msb; i++) {
if ((i % 2) == 0) // if i mod 2 == 0, we clear the bit
num &= ~(1 << (msb - i)); // clear_bit (make it 0)
else
num |= (1 << (msb - i)); // set_bit (make it 1)
}
printf ("\n The resulting number is: %u\n\n", num);
return 0;
}
output:
$ ./bin/bas
Enter a number: 10
The most significant bit (msb): 3
The resulting number is: 13
$ ./bin/bas
Enter a number: 55
The most significant bit (msb): 5
The resulting number is: 53

Can scanf() turn non-zero input into zero

In the following code, the scanf() in main() turns one of the input numbers from a non-zero number into zero, as shown by a debugging printf() in the while loop. I've tested it on several compilers but only to keep getting the same result. Please help me out by telling me why this is such. Thank you.
#include <stdio.h>
unsigned srl (unsigned x, int k)
{
/* perform shift arithmetically */
printf("x = %u, (int) x= %d\n", x, (int) x);
unsigned xsra = (int) x >> k;
printf("\nxsra before was: %u\n", xsra);
unsigned test = 0xffffffff;
test <<= ((sizeof (int) << 3) - k); // get e.g., 0xfff00...
printf("test after shift is: %x, xsra & test = %x\n", test, xsra & test);
if (xsra & test == 0) // if xsrl is positve
return xsra;
else
xsra ^= test; // turn 1s into 0s
return xsra;
}
int sra (int x, int k)
{
/* perform shift logically */
int xsrl = (unsigned) x >> k;
unsigned test = 0xffffffff;
test << ((sizeof (int) << 3) - k + 1); // get e.g., 0xffff00...
if (xsrl & test == 0) // if xsrl is positve
return xsrl;
else
xsrl |= test;
return xsrl;
}
int main(void)
{
int a;
unsigned b;
unsigned short n;
puts("Enter an integer and a positive integer (q or negative second number to quit): ");
while(scanf("%d%u", &a, &b) == 2 && b > 0)
{
printf("Enter the number of shifts (between 0 and %d): ", (sizeof (int) << 3) - 1);
scanf("%d", &n);
if (n < 0 || n >= ((sizeof (int)) << 3))
{
printf("The number of shifts should be between 0 and %d.\n", ((sizeof (int)) << 3) - 1);
break;
}
printf("\nBefore shifting, int a = %d, unsigned b = %u\n", a, b);
a = sra(a, n);
b = srl(b, n);
printf("\nAfter shifting, int a = %d, unsigned b = %u\n", a, b);
puts("\nEnter an integer and a positive integer (q or negative second number to quit): ");
}
puts("Done!");
return 0;
}
The problem is that n is an unsigned short, which has less size than a normal int. When you call scanf("%d", &n);, it reads the value into n and potentially overwrite the existing b value if b has the memory location right after n.
All you have to do is to change that problematic line into:
scanf("%hu", &n);
the h is a modifier for unsigned short int, from here.

How to Modify a specific Byte in an Interger

I have the following code -
int main ()
{
unsigned int u4Val = 0xAABBCCDD;
unsigned char u1User_Val = 0x00;
int Byte_Location = 0;
printf ("\n %08X \n", val);
printf ("\n Enter Byte Location : ");
scanf ("%d", &Byte_Location); /* Get - 0 or 1 or 2 or 3 */
printf ("\n Enter Value to Write : ");
scanf ("%02X", &u1User_Val);
/*====== Code to Write on the Byte Location in u4Val ======*/
printf ("\n %08X \n", u4Val);
return 0;
}
Sample IO
Case 1:
Input: Byte_Location = 0 and Value = 0x54
Output: 0x54BBCCDD
Case 2:
Input: Byte_Location = 1 and Value = 0x21
Output: 0xAA21CCDD
Case 3:
Input: Byte_Location = 2 and Value = 0xFB
Output: 0xAABBFBDD
Case 4:
Input: Byte_Location = 3 and Value = 0x32
Output: 0xAABBCC32
Please help me to code on the pending part. Thanks in advance.
Simply use unsigned bit shifts.
#include <assert.h>
#include <limits.h>
#include <stdio.h>
unsigned ByteReplace(unsigned x, unsigned byte_index, unsigned char byte_new) {
assert(sizeof x * CHAR_BIT >= 4 * 8);
printf("Input: Byte_Location = %u and Value = 0x%02X\n", byte_index,
byte_new);
// Typically I'd expect byte_index to imply the least significant byte. OP has otherwise
byte_index = 3 - byte_index;
unsigned mask = 0xFFu << byte_index * 8;
unsigned y = (~mask & x) | (byte_new << byte_index * 8);
printf("Output: 0x%08X\n", y);
return y;
}
int main(void) {
unsigned int u4Val = 0xAABBCCDD;
ByteReplace(u4Val, 0, 0x54);
ByteReplace(u4Val, 1, 0x21);
ByteReplace(u4Val, 2, 0xFB);
ByteReplace(u4Val, 3, 0x32);
return 0;
}
Output
Input: Byte_Location = 0 and Value = 0x54
Output: 0x54BBCCDD
Input: Byte_Location = 1 and Value = 0x21
Output: 0xAA21CCDD
Input: Byte_Location = 2 and Value = 0xFB
Output: 0xAABBFBDD
Input: Byte_Location = 3 and Value = 0x32
Output: 0xAABBCC32
int a;
((char*)&a)[0]=0x54
((char*)&a)[1]=0x21
((char*)&a)[2]=0xFB
((char*)&a)[3]=0x32
it is preferably to use bitwise shifting, but this one is easy to use and remember.

Read Hex from a file and convert 2 Bytes into Signed int

I have a file in this format:
F2,80,FF,CF,0F,00,A2,XXXX,XXXX,XXXX,01FE,00
I need to take bytes 3 and 4 and combine them into a signed integer.
For example I should extract FF and CF and combine them to 0xFFCF. This should give me a signed value of -49.
The code that I have is here:
int main()
{
char buffer[1024] ;
char *record,*line;
uint8_t val;
uint8_t msb, lsb;
int16_t rate;
int i=0,j=0;
int mat[100][100];
FILE *fstream = fopen("log1.txt","r");
if(fstream == NULL)
{
printf("\n file opening failed ");
return -1 ;
}
while((line=fgets(buffer,sizeof(buffer),fstream))!=NULL)
{
record = strtok(line,",");
int count = 0;
while(record != NULL)
{
count++;
if (count == 3)
{
printf("string:%s\n", record);
sscanf(record, "%02X", &msb);
printf("MSB: %01X\n",msb) ;
}
if (count == 4)
{
printf("string:%s\n", record);
sscanf(record, "%02X", &lsb);
printf("lsb: %01X\n",lsb);
}
if (count == 5)
{
int16_t value = (short)(((msb) & 0xFF) << 8 | (lsb) & 0xFF);
printf("rate: %.2f\n", value*0.03125);
getchar();
}
record = strtok(NULL,",");
}
++i ;
}
return 0;
}
The exact output I see from my code is:
string:FF
MSB: FF
string:CD
lsb: CD
HEX: 00CD
rate: 6.41
I would expect rate to come out as: -1.59
I never seem to see negative numbers, and the values I get are too small.
Rather than using different variable types to try and get the behaviour that you want, how about just being explicit about it? Like so:
#include <stdio.h>
int main(int argc, char *argv[])
{
int msb = 0xff;
int lsb = 0xcf;
int value = (((msb & 0xff) << 8) | (lsb & 0xff));
if (value >= 0x8000) value = -(0x10000 - value);
printf("%d\n", value);
return 0;
}
Here is how I got the code to work:
int16_t hexToInt(char* msb, char* lsb)
{
char toparse[50];
strcpy(toparse, msb);
strcat(toparse,lsb);
int16_t number = (int16_t)strtol(toparse, NULL, 16);
return number;
}
int main()
{
char buffer[1024] ;
char *record,*line;
uint8_t val;
char msb[16], lsb[16];
int16_t rate;
FILE *fstream = fopen("log1.txt","r");
if(fstream == NULL)
{
printf("\n file opening failed ");
return -1 ;
}
while((line=fgets(buffer,sizeof(buffer),fstream))!=NULL)
{
record = strtok(line,",");
int count = 0;
while(record != NULL)
{
count++;
if (count == 3)
{
printf("string:%s\n", record);
strcpy(msb, record);
}
if (count == 4)
{
printf("string:%s\n", record);
strcpy(lsb,record);
}
if (count == 5)
{
int16_t value = hexToInt(msb,lsb);
printf("rate: %.2f\n", value*0.03125);
getchar();
}
record = strtok(NULL,",");
}
++i ;
}
return 0;
}
The value is indeed 0xFFCF, but when multiplying with 0.03125 it is promoted to higher datatype because of which value looses its signedness.
Just change
printf("rate: %.2f\n", value*0.03125);
to
printf("rate: %.2f\n", ((short)value*0.03125));
With value being -49 or 0xFFCF the output will be
rate: -1.53
Code has undefined behavior. OP's code attempts to save an int sized result into 1-byte locations. A good compiler or one with warnings enabled would warn of this issue.
uint8_t msb, lsb;
...
sscanf(record, "%02X", &msb);
sscanf(record, "%02X", &lsb);
Code could use the correct scanf() specifier
#include <inttypes.h>
sscanf(record, "%02" SCNx8, &msb);
sscanf(record, "%02" SCNx8, &lsb);
or simply a different type
unsigned msb, lsb;
...
sscanf(record, "%02X", &msb);
sscanf(record, "%02X", &lsb);
OP's conversion is suspect:
uint8_t msb, lsb;
int16_t value = (short)(((msb) & 0xFF) << 8 | (lsb) & 0xFF);
printf("rate: %.2f\n", value*0.03125);
Suggest something like #John Bickers The following works even if int is 16-bit.
long value = msb;
value <<= 8;
value += lsb;
if (value >= 0x8000) value -= 0x10000;
printf("value %ld\n", value);
// -49 * 0.03125 --> "-1.53"
printf("rate: %.2f\n", value * 0.03125);
Since OP expects a scaled out of -15.6 from -49, perhaps scaling by 1/pi is needed rather than * 0.03125?

optimising btwoc()

According to OpenID Authentication 2.0, section 4.2,
Arbitrary precision integers MUST be encoded as big-endian signed two's complement binary strings. Henceforth, "btwoc" is a function that takes an arbitrary precision integer and returns its shortest big-endian two's complement representation. All integers that are used with Diffie-Hellman Key Exchange are positive. This means that the left-most bit of the two's complement representation MUST be zero. If it is not, implementations MUST add a zero byte at the front of the string.
Non-normative example:
Base 10 number | btwoc string representation
---------------+----------------------------
0 | "\x00"
127 | "\x7F"
128 | "\x00\x80"
255 | "\x00\xFF"
32768 | "\x00\x80\x00"
I have tried writing my own implementation of btwoc in C, and this is what I have:
typedef struct {
uint8_t *data;
uintmax_t length;
} oid_data;
oid_data *oid_btwoc_r(uintmax_t value, oid_data *ret) {
unsigned fnz = sizeof(uintmax_t) + 1,
i = sizeof(uintmax_t) * 8;
while (--fnz && (!(value >> (i -= 8) & 0xFF)));
/*
If `value' is non-zero, `fnz' now contains the index of the first
non-zero byte in `value', where 1 refers to the least-significant byte.
`fnz' will therefore be in the range [1 .. sizeof(uintmax_t)]. If
`value' is zero, then `fnz' is zero.
*/
if (!value) {
/* The value is zero */
ret->length = 1;
ret->data[0] = 0;
} else if (value >> ((fnz - 1) * 8 + 7)) {
/* The most significant bit of the first non-zero byte is 1 */
ret->length = fnz + 1;
ret->data[0] = 0;
for (i = 1; i <= fnz; i++)
ret->data[1 + fnz - i] =
value >> ((i - 1) * 8);
} else {
/* The most significant bit of the first non-zero byte is 0 */
ret->length = fnz;
for (i = 1; i <= fnz; i++)
ret->data[fnz - i] =
value >> ((i - 1) * 8);
}
return ret;
}
ret->data should point to valid memory of at least sizeof(uintmax_t) + 1 bytes.
It works fine, and I haven't discovered any bugs in the implementation yet, but can it be optimised?
If you keep zero as a special case, you should surely deal with it before the while loop. (Personal bĂȘte noire: I dislike (!value) for (value == 0).)
I've not tried timing this (yet), but this code produces the same answer as yours (at least on the values I tested; see below) and looks simpler to me, not least because it doesn't double up the code to deal with the case where the high bit is set in the most significant byte:
void oid_btwoc_r2(uintmax_t value, oid_data *ret)
{
if (value == 0)
{
ret->data[0] = 0;
ret->length = 1;
return;
}
uintmax_t v0 = value;
uintmax_t v1 = v0;
unsigned n = 0;
while (v0 != 0)
{
n++;
v1 = v0;
v0 >>= 8;
}
//printf("Value: 0x%" PRIXMAX ", v1 = 0x%" PRIXMAX "\n", value, v1);
assert(v1 < 0x100 && v1 != 0);
if (v1 > 0x7F)
n++;
//printf("N = %u\n", n);
for (unsigned i = n; i != 0; i--)
{
ret->data[i-1] = (value & 0xFF);
value >>= 8;
}
ret->length = n;
}
The code I used to test this against your version was:
#include <assert.h>
#include <inttypes.h>
#include <stdio.h>
#include <string.h>
#define DIM(x) (sizeof(x) / sizeof(*(x)))
static void dump_oid_data(FILE *fp, const char *tag, const oid_data *data)
{
fprintf(fp, "%s: length %" PRIuMAX ":", tag, data->length);
for (uintmax_t i = 0; i < data->length; i++)
fprintf(fp, " 0x%02X", data->data[i]);
fputc('\n', fp);
}
int main(void)
{
uintmax_t list[] = { 0, 0x7F, 0x80, 0xFF, 0x100, 0x7FFF, 0x8000, 0xFFFF,
0x10000, 0x7FFFFF, 0x800000, 0xFFFFFF };
for (size_t i = 0; i < DIM(list); i++)
{
uint8_t b1[sizeof(uintmax_t) + 1];
uint8_t b2[sizeof(uintmax_t) + 1];
oid_data v1 = { b1, sizeof(b1) };
oid_data v2 = { b2, sizeof(b2) };
oid_btwoc_r(list[i], &v1);
oid_btwoc_r2(list[i], &v2);
printf("Value: 0x%" PRIXMAX ": ", list[i]);
if (v1.length != v2.length)
printf("Lengths differ (%" PRIuMAX " vs %" PRIuMAX ")\n", v1.length, v2.length);
else if (memcmp(v1.data, v2.data, v1.length) != 0)
{
printf("Data differs!\n");
dump_oid_data(stdout, "oid_btwoc_r1()", &v1);
dump_oid_data(stdout, "oid_btwoc_r2()", &v2);
}
else
{
printf("Values are the same\n");
dump_oid_data(stdout, "oid_btwoc_rN()", &v2);
}
}
return(0);
}
Yes; an early version of the code needed the dump function to see what was going wrong!
Timing
I adapted the original oid_btwoc_r() to a function returning void (no final return) and renamed it oid_btwoc_r1(). I then ran a timing test (on a Mac Mini running MacOS X Lion 10.7.1), and got the timing results:
oid_btwoc_r1(): 4.925386
oid_btwoc_r2(): 4.022604
oid_btwoc_r1(): 4.930649
oid_btwoc_r2(): 4.004344
oid_btwoc_r1(): 4.927602
oid_btwoc_r2(): 4.005756
oid_btwoc_r1(): 4.923356
oid_btwoc_r2(): 4.007910
oid_btwoc_r1(): 4.984037
oid_btwoc_r2(): 4.202986
oid_btwoc_r1(): 5.015747
oid_btwoc_r2(): 4.067265
oid_btwoc_r1(): 4.982333
oid_btwoc_r2(): 4.019807
oid_btwoc_r1(): 4.957866
oid_btwoc_r2(): 4.074712
oid_btwoc_r1(): 4.993991
oid_btwoc_r2(): 4.042422
oid_btwoc_r1(): 4.970930
oid_btwoc_r2(): 4.077203
Consequently, it appears that the oid_btwoc_r2() function is about 20% faster than the original - at least on the data tested. Bigger numbers alter the balance in favour of oid_btwoc_r(), with `oid_btwoc_r1() then being about 20% faster:
oid_btwoc_r1(): 3.671201
oid_btwoc_r2(): 4.605171
oid_btwoc_r1(): 3.669026
oid_btwoc_r2(): 4.575745
oid_btwoc_r1(): 3.673729
oid_btwoc_r2(): 4.659433
oid_btwoc_r1(): 3.684662
oid_btwoc_r2(): 4.671654
oid_btwoc_r1(): 3.730757
oid_btwoc_r2(): 4.645485
oid_btwoc_r1(): 3.764600
oid_btwoc_r2(): 4.673244
oid_btwoc_r1(): 3.669582
oid_btwoc_r2(): 4.610177
oid_btwoc_r1(): 3.664248
oid_btwoc_r2(): 4.813711
oid_btwoc_r1(): 3.675927
oid_btwoc_r2(): 4.630148
oid_btwoc_r1(): 3.681798
oid_btwoc_r2(): 4.614129
Since big numbers are probably more likely than small ones in this context, oid_btwoc_r1() - or the original oid_btwoc_r() - is arguably the better choice.
The test code follows. The uncommented for loop is the 'large number' version which shows oid_btwoc_r1() working faster than oid_btwoc_r2(); the commented out for loop is the 'small number' version which shows oid_btwoc_r2() working faster than oid_btowc_r1().
static void test_converter(const char *tag, void (*function)(uintmax_t, oid_data *))
{
Clock clk;
clk_init(&clk);
clk_start(&clk);
for (uintmax_t i = 0x100000000; i < 0x1000000000000000; i += 0x170000000)
//for (uintmax_t i = 0; i < 0x100000000; i += 17)
{
uint8_t b1[sizeof(uintmax_t) + 1];
oid_data v1 = { b1, sizeof(b1) };
(*function)(i, &v1);
}
clk_stop(&clk);
char buffer[32];
printf("%s: %s\n", tag, clk_elapsed_us(&clk, buffer, sizeof(buffer)));
}
int main(void)
{
for (int i = 0; i < 10; i++)
{
test_converter("oid_btwoc_r1()", oid_btwoc_r1);
test_converter("oid_btwoc_r2()", oid_btwoc_r2);
}
return(0);
}

Resources