625 lines
21 KiB
C++
625 lines
21 KiB
C++
/*
|
|
* util.cpp
|
|
* libmsn
|
|
*
|
|
* Created by Mark Rowe on Mon Mar 22 2004.
|
|
* Refactored by Tiago Salem Herrmann on 08/2007.
|
|
* Copyright (c) 2004 Mark Rowe. All rights reserved.
|
|
* Copyright (c) 2007 Tiago Salem Herrmann. All rights reserved
|
|
*
|
|
* 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.
|
|
*
|
|
* This program is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with this program; if not, write to the Free Software
|
|
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
|
*/
|
|
#include <iostream>
|
|
#include <util.h>
|
|
#include <unistd.h>
|
|
#include <sstream>
|
|
#include <errno.h>
|
|
#include <cctype>
|
|
#include <fstream>
|
|
#include <openssl/rand.h>
|
|
#include <cstring>
|
|
#include <sys/timeb.h>
|
|
#include <md5.h>
|
|
#include <libsiren/siren7.h>
|
|
|
|
#ifdef _WIN32
|
|
#define random rand
|
|
#endif
|
|
|
|
namespace MSN
|
|
{
|
|
std::pair<std::string, int> splitServerAddress(const std::string & address, int default_port)
|
|
{
|
|
size_t pos;
|
|
std::string host = address;
|
|
int port = default_port;
|
|
|
|
if ((pos = address.find(":")) != std::string::npos)
|
|
{
|
|
std::string port_s = address.substr(pos + 1);
|
|
host = address.substr(0, pos);
|
|
port = decimalFromString(port_s);
|
|
}
|
|
|
|
if (host == "" || port < 0)
|
|
throw std::runtime_error("Invalid zero-length address or negative port number!");
|
|
|
|
return std::make_pair(host, port);
|
|
}
|
|
|
|
std::string decodeURL(const std::string & s)
|
|
{
|
|
std::string out;
|
|
std::string::const_iterator i;
|
|
|
|
for (i = s.begin(); i != s.end(); i++)
|
|
{
|
|
if (*i == '%')
|
|
{
|
|
char entity[3] = {0, 0, 0};
|
|
if (++i == s.end())
|
|
break;
|
|
|
|
entity[0] = *i;
|
|
|
|
bool doBreak = false;
|
|
if (++i != s.end())
|
|
entity[1] = *i;
|
|
else
|
|
doBreak = true;
|
|
|
|
int c = strtol(entity, NULL, 16);
|
|
out += c;
|
|
|
|
if (doBreak)
|
|
break;
|
|
}
|
|
else
|
|
out += *i;
|
|
}
|
|
return out;
|
|
}
|
|
|
|
std::string encodeURL(const std::string & s)
|
|
{
|
|
std::string out;
|
|
std::string::const_iterator i;
|
|
|
|
for (i = s.begin(); i != s.end(); i++)
|
|
{
|
|
if(!(isalpha(*i) || isdigit(*i)))
|
|
{
|
|
unsigned char high_nibble = ((unsigned char) *i) >> 4;
|
|
unsigned char low_nibble = ((unsigned char) *i) & 0x0F;
|
|
out += '%';
|
|
out += (high_nibble < 0x0A ? '0' + high_nibble : 'A' + high_nibble - 0x0A);
|
|
out += (low_nibble < 0x0A ? '0' + low_nibble : 'A' + low_nibble - 0x0A);
|
|
|
|
continue;
|
|
}
|
|
out += *i;
|
|
}
|
|
|
|
return out;
|
|
}
|
|
|
|
std::vector<std::string> splitString(const std::string & s, const std::string & sep, bool suppressBlanks)
|
|
{
|
|
std::vector<std::string> array;
|
|
size_t position, last_position;
|
|
|
|
last_position = position = 0;
|
|
while (position + sep.size() <= s.size())
|
|
{
|
|
if (s[position] == sep[0] && s.substr(position, sep.size()) == sep)
|
|
{
|
|
if (!suppressBlanks || position - last_position > 0)
|
|
array.push_back(s.substr(last_position, position - last_position));
|
|
last_position = position = position + sep.size();
|
|
}
|
|
else
|
|
position++;
|
|
}
|
|
if (!suppressBlanks || last_position - s.size())
|
|
array.push_back(s.substr(last_position));
|
|
|
|
return array;
|
|
}
|
|
|
|
int nocase_cmp(const std::string & s1, const std::string& s2)
|
|
{
|
|
std::string::const_iterator it1, it2;
|
|
|
|
for (it1 = s1.begin(), it2 = s2.begin();
|
|
it1 != s1.end() && it2 != s2.end();
|
|
++it1, ++it2)
|
|
{
|
|
if (std::toupper(*it1) != std::toupper(*it2))
|
|
return std::toupper(*it1) - std::toupper(*it2);
|
|
}
|
|
size_t size1 = s1.size(), size2 = s2.size();
|
|
return (int) (size1 - size2);
|
|
}
|
|
|
|
std::string toStr(int var) {
|
|
std::ostringstream tmp; tmp << var; return tmp.str();
|
|
}
|
|
|
|
std::string unsignedToStr(unsigned int var) {
|
|
std::ostringstream tmp; tmp << var; return tmp.str();
|
|
}
|
|
|
|
unsigned int decimalFromString(const std::string & s) throw (std::logic_error)
|
|
{
|
|
unsigned int result = strtol(s.c_str(), NULL, 10);
|
|
errno = 0;
|
|
if (result == 0 && errno != 0)
|
|
throw std::logic_error(strerror(errno));
|
|
return result;
|
|
}
|
|
|
|
std::string hmac_sha(std::string key, std::string message)
|
|
{
|
|
unsigned int buf_len=0;
|
|
unsigned char buf[50];
|
|
memset(&buf,0,50);
|
|
HMAC(EVP_sha1(), key.c_str(), key.length(), (const unsigned char*)message.c_str(), message.length(), buf, &buf_len);
|
|
std::string a((char *)buf,buf_len);
|
|
return a;
|
|
}
|
|
|
|
std::string derive_key(std::string key, std::string magic)
|
|
{
|
|
std::string hash1(hmac_sha(key, magic));
|
|
std::string hash2(hmac_sha(key, hash1+magic));
|
|
std::string hash3(hmac_sha(key, hash1));
|
|
std::string hash4(hmac_sha(key, hash3+magic));
|
|
std::string final(hash2+hash4.substr(0,4));
|
|
return final;
|
|
}
|
|
|
|
std::string b64_encode(const char *input, int t)
|
|
{
|
|
BIO *mbio, *b64bio, *bio;
|
|
char *outbuf;
|
|
int inlen, outlen;
|
|
char *output;
|
|
|
|
mbio = BIO_new(BIO_s_mem());
|
|
b64bio = BIO_new(BIO_f_base64());
|
|
BIO_set_flags(b64bio, BIO_FLAGS_BASE64_NO_NL);
|
|
bio = BIO_push(b64bio, mbio);
|
|
|
|
inlen = t ;
|
|
if (BIO_write(bio, input, inlen) != inlen) {
|
|
return "";
|
|
}
|
|
BIO_flush(bio);
|
|
|
|
outlen = BIO_get_mem_data(bio, &outbuf);
|
|
|
|
output = (char*) malloc(outlen+1);
|
|
memcpy(output, outbuf, outlen);
|
|
output[outlen] = '\0';
|
|
std::string output1(output);
|
|
BIO_free_all(bio);
|
|
free(output);
|
|
|
|
return output1;
|
|
}
|
|
|
|
std::string b64_decode(const char *input)
|
|
{
|
|
BIO *mbio, *b64bio, *bio;
|
|
int inlen, outlen;
|
|
char *output;
|
|
|
|
mbio = BIO_new_mem_buf((void *)input, -1);
|
|
b64bio = BIO_new(BIO_f_base64());
|
|
BIO_set_flags(b64bio, BIO_FLAGS_BASE64_NO_NL);
|
|
bio = BIO_push(b64bio, mbio);
|
|
|
|
inlen = strlen(input);
|
|
outlen = inlen*2;
|
|
|
|
output = (char*) malloc(outlen+1);
|
|
|
|
if ((outlen = BIO_read(bio, output, outlen)) <= 0) {
|
|
return "";
|
|
}
|
|
output[outlen] = '\0';
|
|
std::string output1(output, outlen);
|
|
free(output);
|
|
BIO_free_all(bio);
|
|
|
|
return output1;
|
|
}
|
|
|
|
std::string mdi_encrypt(std::string key, std::string nonce)
|
|
{
|
|
tagMSGRUSRKEY MSGUSRKEY;
|
|
std::string key1,key2,key3;
|
|
|
|
key1 = b64_decode(key.c_str());
|
|
key2 = derive_key(key1, "WS-SecureConversationSESSION KEY HASH");
|
|
key3 = derive_key(key1, "WS-SecureConversationSESSION KEY ENCRYPTION");
|
|
|
|
std::string hash = hmac_sha(key2, nonce);
|
|
|
|
unsigned char workvec[8];
|
|
RAND_bytes(workvec, 8);
|
|
des_key_schedule ks1,ks2,ks3;
|
|
|
|
const char *one=key3.c_str();
|
|
const char *two=key3.c_str()+8;
|
|
const char *three=key3.c_str()+16;
|
|
|
|
des_set_key((C_Block *)one,ks1);
|
|
des_set_key((C_Block *)two,ks2);
|
|
des_set_key((C_Block *)three,ks3);
|
|
|
|
unsigned char output[72];
|
|
memset(&output,0,72);
|
|
|
|
memcpy(&MSGUSRKEY.aIVBytes, &workvec, sizeof(workvec));
|
|
memcpy(&MSGUSRKEY.aHashBytes, hash.c_str() , hash.length());
|
|
|
|
// ugly, but I think it is working properly
|
|
std::ostringstream buf_;
|
|
buf_ << nonce << "\x08\x08\x08\x08\x08\x08\x08\x08";
|
|
DES_ede3_cbc_encrypt((const unsigned char*)buf_.str().c_str(),output,buf_.str().size(),&ks1,&ks2,&ks3,(C_Block *)workvec,DES_ENCRYPT);
|
|
|
|
MSGUSRKEY.uStructHeaderSize=28;
|
|
MSGUSRKEY.uCryptMode=1;
|
|
MSGUSRKEY.uCipherType=0x6603;
|
|
MSGUSRKEY.uHashType=0x8004;
|
|
MSGUSRKEY.uIVLen=8;
|
|
MSGUSRKEY.uHashLen=hash.length();
|
|
MSGUSRKEY.uCipherLen=72;
|
|
|
|
// set
|
|
memcpy(&MSGUSRKEY.aCipherBytes,output, 72);
|
|
unsigned char a[129]; // last is \0 to b64_encode
|
|
memset(&a,0,129);
|
|
memcpy(&a, &MSGUSRKEY, sizeof(tagMSGRUSRKEY));
|
|
|
|
return b64_encode((const char*)a,128);
|
|
}
|
|
|
|
void DoMSNP11Challenge(const char *szChallenge, char *szOutput)
|
|
{
|
|
int i;
|
|
md5_state_t state;
|
|
md5_byte_t digest[16];
|
|
md5_init(&state);
|
|
md5_append(&state, (const md5_byte_t *)szChallenge, strlen(szChallenge));
|
|
md5_append(&state, (const md5_byte_t *)szClientCode, strlen(szClientCode));
|
|
md5_finish(&state, digest);
|
|
|
|
unsigned char pMD5Hash[16];
|
|
memcpy(pMD5Hash,digest,16);
|
|
int *pMD5Parts=(int *)digest;
|
|
for (i=0; i<4; i++) {
|
|
pMD5Parts[i]&=0x7FFFFFFF;
|
|
}
|
|
int nchlLen=strlen(szChallenge)+strlen(szClientID);
|
|
if (nchlLen%8!=0)
|
|
nchlLen+=8-(nchlLen%8);
|
|
char *chlString=new char[nchlLen];
|
|
memset(chlString,'0',nchlLen);
|
|
memcpy(chlString,szChallenge,strlen(szChallenge));
|
|
memcpy(chlString+strlen(szChallenge),szClientID,strlen(szClientID));
|
|
int *pchlStringParts=(int *)chlString;
|
|
|
|
long long nHigh=0;
|
|
long long nLow=0;
|
|
|
|
for (i=0; i<(nchlLen/4)-1; i+=2) {
|
|
long long temp=pchlStringParts[i];
|
|
temp=(pMD5Parts[0] * (((0x0E79A9C1 * (long long)pchlStringParts[i]) % 0x7FFFFFFF)+nHigh) + pMD5Parts[1])%0x7FFFFFFF;
|
|
nHigh=(pMD5Parts[2] * (((long long)pchlStringParts[i+1]+temp) % 0x7FFFFFFF) + pMD5Parts[3]) % 0x7FFFFFFF;
|
|
nLow=nLow + nHigh + temp;
|
|
}
|
|
nHigh=(nHigh+pMD5Parts[1]) % 0x7FFFFFFF;
|
|
nLow=(nLow+pMD5Parts[3]) % 0x7FFFFFFF;
|
|
delete[] chlString;
|
|
|
|
unsigned int *pNewHash=(unsigned int *)pMD5Hash;
|
|
|
|
pNewHash[0]^=nHigh;
|
|
pNewHash[1]^=nLow;
|
|
pNewHash[2]^=nHigh;
|
|
pNewHash[3]^=nLow;
|
|
|
|
char szHexChars[]="0123456789abcdef";
|
|
for (i=0; i<16; i++) {
|
|
szOutput[i*2]=szHexChars[(pMD5Hash[i]>>4)&0xF];
|
|
szOutput[(i*2)+1]=szHexChars[pMD5Hash[i]&0xF];
|
|
}
|
|
}
|
|
// 4-byte number
|
|
unsigned int little2big_endian(unsigned int i)
|
|
{
|
|
return((i&0xff)<<24)+((i&0xff00)<<8)+((i&0xff0000)>>8)+((i>>24)&0xff);
|
|
}
|
|
|
|
int FileSize(const char* sFileName)
|
|
{
|
|
std::ifstream f;
|
|
f.open(sFileName, std::ios_base::binary | std::ios_base::in);
|
|
if (!f.good() || f.eof() || !f.is_open()) { return 0; }
|
|
f.seekg(0, std::ios_base::beg);
|
|
std::ifstream::pos_type begin_pos = f.tellg();
|
|
f.seekg(0, std::ios_base::end);
|
|
return static_cast<int>(f.tellg() - begin_pos);
|
|
}
|
|
|
|
std::string new_branch()
|
|
{
|
|
struct timeb t;
|
|
ftime(&t);
|
|
char branch[100];
|
|
srand(t.millitm);
|
|
unsigned int a=random();
|
|
srand(a);
|
|
unsigned short b=random();
|
|
srand(b);
|
|
unsigned short c=random();
|
|
srand(c);
|
|
unsigned short d=random();
|
|
srand(d);
|
|
double e=random();
|
|
sprintf(branch,"{%.8X-%.4X-%.4X-%.4X-%.12X}",a,b,c,d,(unsigned int)e);
|
|
std::string newbranch(branch);
|
|
return newbranch;
|
|
}
|
|
|
|
// Code from http://search.cpan.org/src/DANKOGAI/Jcode-2.06/Unicode/uni.c
|
|
U32 _ucs2_utf8(U8 *dst, U8 *src, U32 nchar)
|
|
{
|
|
U32 ucs2;
|
|
U32 result = 0;
|
|
for (nchar /= 2; nchar > 0; nchar--, src += 2) {
|
|
ucs2 = src[0]*256 + src[1];
|
|
if (ucs2 < 0x80){ /* 1 byte */
|
|
*dst++ = ucs2;
|
|
result += 1;
|
|
}else if (ucs2 < 0x800){ /* 2 bytes */
|
|
*dst++ = (0xC0 | (ucs2 >> 6));
|
|
*dst++ = (0x80 | (ucs2 & 0x3F));
|
|
result += 2;
|
|
}else{ /* 3 bytes */
|
|
*dst++ = (0xE0 | (ucs2 >> 12));
|
|
*dst++ = (0x80 | ((ucs2 >> 6) & 0x3F));
|
|
*dst++ = (0x80 | (ucs2 & 0x3F));
|
|
result += 3;
|
|
}
|
|
}
|
|
*dst = '\0';
|
|
return result;
|
|
}
|
|
|
|
U32 _utf8_ucs2(U8 *dst, U8 *src)
|
|
{
|
|
U32 ucs2;
|
|
U8 c1, c2, c3;
|
|
U32 result = 0;
|
|
|
|
for(; *src != '\0'; src++, result++){
|
|
if (*src < 0x80) { /* 1 byte */
|
|
ucs2 = *src;
|
|
}else if (*src < 0xE0){ /* 2 bytes */
|
|
if (src[1]){
|
|
c1 = *src++; c2 = *src;
|
|
ucs2 = ((c1 & 0x1F) << 6) | (c2 & 0x3F);
|
|
}else{
|
|
ucs2 = FB_UNI;
|
|
}
|
|
}else{ /* 3 bytes */
|
|
if (src[1] && src[2]){
|
|
c1 = *src++; c2 = *src++; c3 = *src;
|
|
ucs2 = ((c1 & 0x0F) << 12) | ((c2 & 0x3F) << 6)| (c3 & 0x3F);
|
|
}else{
|
|
ucs2 = FB_UNI;
|
|
if (src[1])
|
|
src++;
|
|
}
|
|
}
|
|
*dst++ = (ucs2 & 0xff00) >> 8; /* 1st byte */
|
|
*dst++ = (ucs2 & 0xff); /* 2nd byte */;
|
|
}
|
|
return result * 2;
|
|
}
|
|
|
|
// convert from siren codec to a regular wav file
|
|
void
|
|
libmsn_Siren7_DecodeVoiceClip(std::string input_file)
|
|
{
|
|
FILE * input;
|
|
FILE * output;
|
|
riff_data riff_header;
|
|
wav_data current_chunk;
|
|
fmt_chunk_ex fmt_info;
|
|
unsigned char *out_data = NULL;
|
|
unsigned char *out_ptr = NULL;
|
|
unsigned char in_buffer[40];
|
|
unsigned int file_offset;
|
|
unsigned int chunk_offset;
|
|
|
|
std::string new_voice(input_file.c_str());
|
|
std::string old_voice = new_voice + "-old";
|
|
rename(new_voice.c_str(), old_voice.c_str());
|
|
|
|
SirenDecoder decoder = Siren7_NewDecoder (16000);
|
|
|
|
input = fopen (old_voice.c_str(), "rb");
|
|
output = fopen (new_voice.c_str(), "wb");
|
|
|
|
file_offset = 0;
|
|
fread (&riff_header, sizeof (riff_data), 1, input);
|
|
file_offset += sizeof (riff_data);
|
|
|
|
riff_header.chunk_id = GUINT32_FROM_LE (riff_header.chunk_id);
|
|
riff_header.chunk_size = GUINT32_FROM_LE (riff_header.chunk_size);
|
|
riff_header.type_id = GUINT32_FROM_LE (riff_header.type_id);
|
|
|
|
if (riff_header.chunk_id == RIFF_ID && riff_header.type_id == WAVE_ID)
|
|
{
|
|
while (file_offset < riff_header.chunk_size)
|
|
{
|
|
fread (¤t_chunk, sizeof (wav_data), 1, input);
|
|
file_offset += sizeof (wav_data);
|
|
current_chunk.chunk_id = GUINT32_FROM_LE (current_chunk.chunk_id);
|
|
current_chunk.chunk_size = GUINT32_FROM_LE (current_chunk.chunk_size);
|
|
|
|
chunk_offset = 0;
|
|
if (current_chunk.chunk_id == FMT_ID)
|
|
{
|
|
fread (&fmt_info, sizeof (fmt_chunk), 1, input);
|
|
/* Should convert from LE the fmt_info structure, but it's not necessary... */
|
|
if (current_chunk.chunk_size > sizeof (fmt_chunk))
|
|
{
|
|
fread (&(fmt_info.extra_size), sizeof (short), 1, input);
|
|
fmt_info.extra_size = GUINT32_FROM_LE (fmt_info.extra_size);
|
|
fmt_info.extra_content = (unsigned char *) malloc (fmt_info.extra_size);
|
|
fread (fmt_info.extra_content, fmt_info.extra_size, 1, input);
|
|
}
|
|
else
|
|
{
|
|
fmt_info.extra_size = 0;
|
|
fmt_info.extra_content = NULL;
|
|
}
|
|
}
|
|
else if (current_chunk.chunk_id == DATA_ID)
|
|
{
|
|
out_data = (unsigned char *) malloc (current_chunk.chunk_size * 16);
|
|
out_ptr = out_data;
|
|
while (chunk_offset + 40 <= current_chunk.chunk_size)
|
|
{
|
|
fread (in_buffer, 1, 40, input);
|
|
Siren7_DecodeFrame (decoder, in_buffer, out_ptr);
|
|
out_ptr += 640;
|
|
chunk_offset += 40;
|
|
}
|
|
fread (in_buffer, 1, current_chunk.chunk_size - chunk_offset, input);
|
|
}
|
|
else
|
|
{
|
|
fseek (input, current_chunk.chunk_size, SEEK_CUR);
|
|
}
|
|
|
|
file_offset += current_chunk.chunk_size;
|
|
}
|
|
}
|
|
|
|
/* The WAV heder should be converted TO LE, but should be done inside the library and it's not important for now ... */
|
|
fwrite (&(decoder->WavHeader), sizeof (decoder->WavHeader), 1, output);
|
|
fwrite (out_data, 1, GUINT32_FROM_LE (decoder->WavHeader.DataSize), output);
|
|
fclose (output);
|
|
|
|
Siren7_CloseDecoder (decoder);
|
|
|
|
free (out_data);
|
|
free (fmt_info.extra_content);
|
|
|
|
// remove the siren encoded file
|
|
unlink(old_voice.c_str());
|
|
}
|
|
|
|
// convert to siren codec from a regular wav file
|
|
void
|
|
libmsn_Siren7_EncodeVoiceClip(std::string input_file)
|
|
{
|
|
FILE * input;
|
|
FILE * output;
|
|
riff_data riff_header;
|
|
wav_data current_chunk;
|
|
fmt_chunk_ex fmt_info;
|
|
unsigned char *out_data = NULL;
|
|
unsigned char *out_ptr = NULL;
|
|
unsigned char InBuffer[640];
|
|
unsigned int fileOffset;
|
|
unsigned int chunkOffset;
|
|
|
|
SirenEncoder encoder = Siren7_NewEncoder(16000);
|
|
|
|
std::string new_voice(input_file.c_str());
|
|
std::string old_voice = new_voice + "-old";
|
|
rename(new_voice.c_str(), old_voice.c_str());
|
|
|
|
input = fopen (old_voice.c_str(), "rb");
|
|
output = fopen (new_voice.c_str(), "wb");
|
|
|
|
fileOffset = 0;
|
|
fread(&riff_header, sizeof(riff_data), 1, input);
|
|
fileOffset += sizeof(riff_data);
|
|
|
|
riff_header.chunk_id = GUINT32_FROM_LE(riff_header.chunk_id);
|
|
riff_header.chunk_size = GUINT32_FROM_LE(riff_header.chunk_size);
|
|
riff_header.type_id = GUINT32_FROM_LE(riff_header.type_id);
|
|
|
|
if (riff_header.chunk_id == RIFF_ID && riff_header.type_id == WAVE_ID) {
|
|
while (fileOffset < riff_header.chunk_size) {
|
|
fread(¤t_chunk, sizeof(wav_data), 1, input);
|
|
fileOffset += sizeof(wav_data);
|
|
current_chunk.chunk_id = GUINT32_FROM_LE(current_chunk.chunk_id);
|
|
current_chunk.chunk_size = GUINT32_FROM_LE(current_chunk.chunk_size);
|
|
|
|
chunkOffset = 0;
|
|
if (current_chunk.chunk_id == FMT__ID) {
|
|
fread(&fmt_info, sizeof(fmt_chunk), 1, input);
|
|
/* Should convert from LE the fmt_info structure, but it's not necessary... */
|
|
if (current_chunk.chunk_size > sizeof(fmt_chunk)) {
|
|
fread(&(fmt_info.extra_size), sizeof(short), 1, input);
|
|
fmt_info.extra_size= GUINT32_FROM_LE(fmt_info.extra_size);
|
|
fmt_info.extra_content = (unsigned char *) malloc (fmt_info.extra_size);
|
|
fread(fmt_info.extra_content, fmt_info.extra_size, 1, input);
|
|
} else {
|
|
fmt_info.extra_size = 0;
|
|
fmt_info.extra_content = NULL;
|
|
}
|
|
} else if (current_chunk.chunk_id == DATA_ID) {
|
|
out_data = (unsigned char *) malloc(current_chunk.chunk_size / 16);
|
|
out_ptr = out_data;
|
|
while (chunkOffset + 640 <= current_chunk.chunk_size) {
|
|
fread(InBuffer, 1, 640, input);
|
|
Siren7_EncodeFrame(encoder, InBuffer, out_ptr);
|
|
out_ptr += 40;
|
|
chunkOffset += 640;
|
|
}
|
|
fread(InBuffer, 1, current_chunk.chunk_size - chunkOffset, input);
|
|
} else {
|
|
fseek(input, current_chunk.chunk_size, SEEK_CUR);
|
|
}
|
|
fileOffset += current_chunk.chunk_size;
|
|
}
|
|
}
|
|
|
|
/* The WAV heder should be converted TO LE, but should be done inside the library and it's not important for now ... */
|
|
fwrite(&(encoder->WavHeader), sizeof(encoder->WavHeader), 1, output);
|
|
fwrite(out_data, 1, GUINT32_FROM_LE(encoder->WavHeader.DataSize), output);
|
|
fclose(output);
|
|
|
|
Siren7_CloseEncoder(encoder);
|
|
|
|
free(out_data);
|
|
if (fmt_info.extra_content != NULL)
|
|
free(fmt_info.extra_content);
|
|
|
|
// remove the siren encoded file
|
|
unlink(old_voice.c_str());
|
|
}
|
|
}
|