347 lines
5.7 KiB
C++
347 lines
5.7 KiB
C++
#include "ebmlreadhelpers.hpp"
|
|
#include "imkvreader.hpp"
|
|
#include "memory.hpp"
|
|
|
|
#include <stddef.h>
|
|
#include <assert.h>
|
|
#include <limits.h>
|
|
|
|
namespace mkvparser
|
|
{
|
|
|
|
long long ReadUInt(IMkvReader* pReader, long long pos, long& len)
|
|
{
|
|
assert(pReader);
|
|
assert(pos >= 0);
|
|
|
|
int status;
|
|
|
|
//#ifdef _DEBUG
|
|
// long long total, available;
|
|
// status = pReader->Length(&total, &available);
|
|
// assert(status >= 0);
|
|
// assert((total < 0) || (available <= total));
|
|
// assert(pos < available);
|
|
// assert((available - pos) >= 1); //assume here max u-int len is 8
|
|
//#endif
|
|
|
|
len = 1;
|
|
|
|
unsigned char b;
|
|
|
|
status = pReader->Read(pos, 1, &b);
|
|
|
|
if (status < 0) //error or underflow
|
|
return status;
|
|
|
|
if (status > 0) //interpreted as "underflow"
|
|
return E_BUFFER_NOT_FULL;
|
|
|
|
if (b == 0) //we can't handle u-int values larger than 8 bytes
|
|
return E_FILE_FORMAT_INVALID;
|
|
|
|
unsigned char m = 0x80;
|
|
|
|
while (!(b & m))
|
|
{
|
|
m >>= 1;
|
|
++len;
|
|
}
|
|
|
|
//#ifdef _DEBUG
|
|
// assert((available - pos) >= len);
|
|
//#endif
|
|
|
|
long long result = b & (~m);
|
|
++pos;
|
|
|
|
for (int i = 1; i < len; ++i)
|
|
{
|
|
status = pReader->Read(pos, 1, &b);
|
|
|
|
if (status < 0)
|
|
{
|
|
len = 1;
|
|
return status;
|
|
}
|
|
|
|
if (status > 0)
|
|
{
|
|
len = 1;
|
|
return E_BUFFER_NOT_FULL;
|
|
}
|
|
|
|
result <<= 8;
|
|
result |= b;
|
|
|
|
++pos;
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
long long GetUIntLength(
|
|
IMkvReader* pReader,
|
|
long long pos,
|
|
long& len)
|
|
{
|
|
assert(pReader);
|
|
assert(pos >= 0);
|
|
|
|
long long total, available;
|
|
|
|
int status = pReader->Length(&total, &available);
|
|
assert(status >= 0);
|
|
assert((total < 0) || (available <= total));
|
|
|
|
len = 1;
|
|
|
|
if (pos >= available)
|
|
return pos; //too few bytes available
|
|
|
|
unsigned char b;
|
|
|
|
status = pReader->Read(pos, 1, &b);
|
|
|
|
if (status < 0)
|
|
return status;
|
|
|
|
assert(status == 0);
|
|
|
|
if (b == 0) //we can't handle u-int values larger than 8 bytes
|
|
return E_FILE_FORMAT_INVALID;
|
|
|
|
unsigned char m = 0x80;
|
|
|
|
while (!(b & m))
|
|
{
|
|
m >>= 1;
|
|
++len;
|
|
}
|
|
|
|
return 0; //success
|
|
}
|
|
|
|
|
|
long long UnserializeUInt(
|
|
IMkvReader* pReader,
|
|
long long pos,
|
|
long long size)
|
|
{
|
|
assert(pReader);
|
|
assert(pos >= 0);
|
|
|
|
if ((size <= 0) || (size > 8))
|
|
return E_FILE_FORMAT_INVALID;
|
|
|
|
long long result = 0;
|
|
|
|
for (long long i = 0; i < size; ++i)
|
|
{
|
|
unsigned char b;
|
|
|
|
const long status = pReader->Read(pos, 1, &b);
|
|
|
|
if (status < 0)
|
|
return status;
|
|
|
|
result <<= 8;
|
|
result |= b;
|
|
|
|
++pos;
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
|
|
long UnserializeFloat(
|
|
IMkvReader* pReader,
|
|
long long pos,
|
|
long long size_,
|
|
double& result)
|
|
{
|
|
assert(pReader);
|
|
assert(pos >= 0);
|
|
|
|
if ((size_ != 4) && (size_ != 8))
|
|
return E_FILE_FORMAT_INVALID;
|
|
|
|
const long size = static_cast<long>(size_);
|
|
|
|
unsigned char buf[8];
|
|
|
|
const int status = pReader->Read(pos, size, buf);
|
|
|
|
if (status < 0) //error
|
|
return status;
|
|
|
|
if (size == 4)
|
|
{
|
|
union
|
|
{
|
|
float f;
|
|
unsigned long ff;
|
|
};
|
|
|
|
ff = 0;
|
|
|
|
for (int i = 0;;)
|
|
{
|
|
ff |= buf[i];
|
|
|
|
if (++i >= 4)
|
|
break;
|
|
|
|
ff <<= 8;
|
|
}
|
|
|
|
result = f;
|
|
}
|
|
else
|
|
{
|
|
assert(size == 8);
|
|
|
|
union
|
|
{
|
|
double d;
|
|
unsigned long long dd;
|
|
};
|
|
|
|
dd = 0;
|
|
|
|
for (int i = 0;;)
|
|
{
|
|
dd |= buf[i];
|
|
|
|
if (++i >= 8)
|
|
break;
|
|
|
|
dd <<= 8;
|
|
}
|
|
|
|
result = d;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
long UnserializeInt(
|
|
IMkvReader* pReader,
|
|
long long pos,
|
|
long size,
|
|
long long& result)
|
|
{
|
|
assert(pReader);
|
|
assert(pos >= 0);
|
|
assert(size > 0);
|
|
assert(size <= 8);
|
|
|
|
{
|
|
signed char b;
|
|
|
|
const long status = pReader->Read(pos, 1, (unsigned char*)&b);
|
|
|
|
if (status < 0)
|
|
return status;
|
|
|
|
result = b;
|
|
|
|
++pos;
|
|
}
|
|
|
|
for (long i = 1; i < size; ++i)
|
|
{
|
|
unsigned char b;
|
|
|
|
const long status = pReader->Read(pos, 1, &b);
|
|
|
|
if (status < 0)
|
|
return status;
|
|
|
|
result <<= 8;
|
|
result |= b;
|
|
|
|
++pos;
|
|
}
|
|
|
|
return 0; //success
|
|
}
|
|
|
|
|
|
long UnserializeString(
|
|
IMkvReader* pReader,
|
|
long long pos,
|
|
long long size_,
|
|
char*& str)
|
|
{
|
|
mem::Free(str);
|
|
str = NULL;
|
|
|
|
if (size_ >= LONG_MAX) //we need (size+1) chars
|
|
return E_FILE_FORMAT_INVALID;
|
|
|
|
const long size = static_cast<long>(size_);
|
|
|
|
str = static_cast<char*>(mem::Allocate(size+1));
|
|
|
|
if (str == NULL)
|
|
return -1;
|
|
|
|
unsigned char* const buf = reinterpret_cast<unsigned char*>(str);
|
|
|
|
const long status = pReader->Read(pos, size, buf);
|
|
|
|
if (status)
|
|
{
|
|
mem::Free(str);
|
|
str = NULL;
|
|
|
|
return status;
|
|
}
|
|
|
|
str[size] = '\0';
|
|
|
|
return 0; //success
|
|
}
|
|
|
|
|
|
long ParseElementHeader(
|
|
IMkvReader* pReader,
|
|
long long& pos,
|
|
long long stop,
|
|
long long& id,
|
|
long long& size)
|
|
{
|
|
if ((stop >= 0) && (pos >= stop))
|
|
return E_FILE_FORMAT_INVALID;
|
|
|
|
long len;
|
|
|
|
id = ReadUInt(pReader, pos, len);
|
|
|
|
if (id < 0)
|
|
return E_FILE_FORMAT_INVALID;
|
|
|
|
pos += len; //consume id
|
|
|
|
if ((stop >= 0) && (pos >= stop))
|
|
return E_FILE_FORMAT_INVALID;
|
|
|
|
size = ReadUInt(pReader, pos, len);
|
|
|
|
if (size < 0)
|
|
return E_FILE_FORMAT_INVALID;
|
|
|
|
pos += len; //consume length of size
|
|
|
|
//pos now designates payload
|
|
|
|
if ((stop >= 0) && ((pos + size) > stop))
|
|
return E_FILE_FORMAT_INVALID;
|
|
|
|
return 0; //success
|
|
}
|
|
|
|
} // namespace mkvparser
|