mirror of
https://github.com/hrydgard/ppsspp.git
synced 2026-11-12 00:59:41 +01:00
Merge pull request #10253 from hrydgard/riff-cleanup
RIFF reader cleanup and sanity checks
This commit is contained in:
3 files changed
+112
-318
No files matched your search
+18
-18
@@ -31,10 +31,10 @@ public:
|
||||
u8 at3_extradata[16];
|
||||
|
||||
int num_channels, sample_rate, numFrames, samplesPerSec, avgBytesPerSec, Nothing;
|
||||
if (file_.descend('RIFF')) {
|
||||
file_.readInt(); //get past 'WAVE'
|
||||
if (file_.descend('fmt ')) { //enter the format chunk
|
||||
int temp = file_.readInt();
|
||||
if (file_.Descend('RIFF')) {
|
||||
file_.ReadInt(); //get past 'WAVE'
|
||||
if (file_.Descend('fmt ')) { //enter the format chunk
|
||||
int temp = file_.ReadInt();
|
||||
int format = temp & 0xFFFF;
|
||||
switch (format) {
|
||||
case 0xFFFE:
|
||||
@@ -50,10 +50,10 @@ public:
|
||||
|
||||
num_channels = temp >> 16;
|
||||
|
||||
samplesPerSec = file_.readInt();
|
||||
avgBytesPerSec = file_.readInt();
|
||||
samplesPerSec = file_.ReadInt();
|
||||
avgBytesPerSec = file_.ReadInt();
|
||||
|
||||
temp = file_.readInt();
|
||||
temp = file_.ReadInt();
|
||||
raw_bytes_per_frame_ = temp & 0xFFFF;
|
||||
Nothing = temp >> 16;
|
||||
|
||||
@@ -64,41 +64,41 @@ public:
|
||||
if (codec == PSP_CODEC_AT3) {
|
||||
// The first two bytes are actually not a useful part of the extradata.
|
||||
// We already read 16 bytes, so make sure there's enough left.
|
||||
if (file_.getCurrentChunkSize() >= 32) {
|
||||
file_.readData(at3_extradata, 16);
|
||||
if (file_.GetCurrentChunkSize() >= 32) {
|
||||
file_.ReadData(at3_extradata, 16);
|
||||
} else {
|
||||
memset(at3_extradata, 0, sizeof(at3_extradata));
|
||||
}
|
||||
}
|
||||
file_.ascend();
|
||||
file_.Ascend();
|
||||
// ILOG("got fmt data: %i", samplesPerSec);
|
||||
} else {
|
||||
ELOG("Error - no format chunk in wav");
|
||||
file_.ascend();
|
||||
file_.Ascend();
|
||||
return;
|
||||
}
|
||||
|
||||
if (file_.descend('data')) { //enter the data chunk
|
||||
int numBytes = file_.getCurrentChunkSize();
|
||||
if (file_.Descend('data')) { //enter the data chunk
|
||||
int numBytes = file_.GetCurrentChunkSize();
|
||||
numFrames = numBytes / raw_bytes_per_frame_; // numFrames
|
||||
|
||||
raw_data_ = (uint8_t *)malloc(numBytes);
|
||||
raw_data_size_ = numBytes;
|
||||
if (/*raw_bytes_per_frame_ == 280 && */ num_channels == 1 || num_channels == 2) {
|
||||
file_.readData(raw_data_, numBytes);
|
||||
file_.ReadData(raw_data_, numBytes);
|
||||
} else {
|
||||
ELOG("Error - bad blockalign or channels");
|
||||
free(raw_data_);
|
||||
raw_data_ = 0;
|
||||
return;
|
||||
}
|
||||
file_.ascend();
|
||||
file_.Ascend();
|
||||
} else {
|
||||
ELOG("Error - no data chunk in wav");
|
||||
file_.ascend();
|
||||
file_.Ascend();
|
||||
return;
|
||||
}
|
||||
file_.ascend();
|
||||
file_.Ascend();
|
||||
} else {
|
||||
ELOG("Could not descend into RIFF file. Data size=%d", (int32_t)data.size());
|
||||
return;
|
||||
@@ -153,7 +153,7 @@ public:
|
||||
}
|
||||
|
||||
private:
|
||||
ChunkFile file_;
|
||||
RIFFReader file_;
|
||||
uint8_t *raw_data_;
|
||||
int raw_data_size_;
|
||||
int raw_offset_;
|
||||
|
||||
+78
-256
@@ -3,287 +3,109 @@
|
||||
#include "file/zip_read.h"
|
||||
#include "file/file_util.h"
|
||||
|
||||
//#define CHUNKDEBUG
|
||||
#include "Common/Log.h"
|
||||
|
||||
ChunkFile::ChunkFile(const char *filename, bool _read) {
|
||||
data=0;
|
||||
fn = filename;
|
||||
numLevels=0;
|
||||
read=_read;
|
||||
pos=0;
|
||||
didFail=false;
|
||||
|
||||
fastMode = read ? true : false;
|
||||
|
||||
if (fastMode) {
|
||||
size_t size;
|
||||
data = (uint8_t *)VFSReadFile(filename, &size);
|
||||
if (!data) {
|
||||
ELOG("Chunkfile fail: %s", filename);
|
||||
didFail = true;
|
||||
return;
|
||||
}
|
||||
eof = (int)size;
|
||||
return;
|
||||
}
|
||||
|
||||
file = openCFile(filename, "wb");
|
||||
if (file) {
|
||||
didFail = false;
|
||||
eof = 0;
|
||||
} else {
|
||||
didFail = true;
|
||||
}
|
||||
inline uint32_t flipID(uint32_t id) {
|
||||
return ((id >> 24) & 0xFF) | ((id >> 8) & 0xFF00) | ((id << 8) & 0xFF0000) | ((id << 24) & 0xFF000000);
|
||||
}
|
||||
|
||||
ChunkFile::ChunkFile(const uint8_t *read_data, int data_size) {
|
||||
data = new uint8_t[data_size];
|
||||
memcpy(data, read_data, data_size);
|
||||
fastMode = true;
|
||||
numLevels = 0;
|
||||
read = true;
|
||||
pos = 0;
|
||||
didFail = false;
|
||||
eof = data_size;
|
||||
RIFFReader::RIFFReader(const uint8_t *data, int dataSize) {
|
||||
data_ = new uint8_t[dataSize];
|
||||
memcpy(data_, data, dataSize);
|
||||
depth_ = 0;
|
||||
pos_ = 0;
|
||||
eof_ = dataSize;
|
||||
fileSize_ = dataSize;
|
||||
}
|
||||
|
||||
ChunkFile::~ChunkFile() {
|
||||
if (fastMode) {
|
||||
delete[] data;
|
||||
} else {
|
||||
fclose(file);
|
||||
}
|
||||
RIFFReader::~RIFFReader() {
|
||||
delete[] data_;
|
||||
}
|
||||
|
||||
int ChunkFile::readInt() {
|
||||
if (data && pos<eof) {
|
||||
pos += 4;
|
||||
if (fastMode)
|
||||
return *(int *)(data + pos - 4);
|
||||
else {
|
||||
int i;
|
||||
if (fread(&i, 1, 4, file) == 4) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
int RIFFReader::ReadInt() {
|
||||
if (data_ && pos_ < eof_ - 3) {
|
||||
pos_ += 4;
|
||||
return *(int *)(data_ + pos_ - 4);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void ChunkFile::writeInt(int i) {
|
||||
fwrite(&i, 1, 4, file);
|
||||
pos += 4;
|
||||
}
|
||||
|
||||
//let's get into the business
|
||||
bool ChunkFile::descend(uint32_t id) {
|
||||
if (numLevels > 30)
|
||||
// let's get into the business
|
||||
bool RIFFReader::Descend(uint32_t intoId) {
|
||||
if (depth_ > 30)
|
||||
return false;
|
||||
|
||||
id = flipID(id);
|
||||
if (read) {
|
||||
bool found = false;
|
||||
intoId = flipID(intoId);
|
||||
bool found = false;
|
||||
|
||||
//save information to restore after the next Ascend
|
||||
stack[numLevels].parentStartLocation = pos;
|
||||
stack[numLevels].parentEOF = eof;
|
||||
// save information to restore after the next Ascend
|
||||
stack[depth_].parentStartLocation = pos_;
|
||||
stack[depth_].parentEOF = eof_;
|
||||
|
||||
ChunkInfo temp = stack[numLevels];
|
||||
// let's search through children..
|
||||
while (pos_ < eof_) {
|
||||
int id = ReadInt();
|
||||
int length = ReadInt();
|
||||
int startLocation = pos_;
|
||||
|
||||
int firstID = 0;
|
||||
//let's search through children..
|
||||
while(pos<eof) {
|
||||
stack[numLevels].ID = readInt();
|
||||
if (firstID == 0) firstID=stack[numLevels].ID|1;
|
||||
stack[numLevels].length = readInt();
|
||||
stack[numLevels].startLocation = pos;
|
||||
|
||||
if (stack[numLevels].ID == id)
|
||||
{
|
||||
found = true;
|
||||
break;
|
||||
} else {
|
||||
seekTo(pos + stack[numLevels].length); //try next block
|
||||
}
|
||||
}
|
||||
|
||||
//if we found nothing, return false so the caller can skip this
|
||||
if (!found) {
|
||||
#ifdef CHUNKDEBUG
|
||||
ILOG("Couldn't find %c%c%c%c", id, id>>8, id>>16, id>>24);
|
||||
#endif
|
||||
stack[numLevels]=temp;
|
||||
seekTo(stack[numLevels].parentStartLocation);
|
||||
if (pos_ + length > fileSize_) {
|
||||
ERROR_LOG(SYSTEM, "Block extends outside of RIFF file - failing descend");
|
||||
pos_ = stack[depth_].parentStartLocation;
|
||||
return false;
|
||||
}
|
||||
|
||||
//descend into it
|
||||
//pos was set inside the loop above
|
||||
eof = stack[numLevels].startLocation + stack[numLevels].length;
|
||||
numLevels++;
|
||||
#ifdef CHUNKDEBUG
|
||||
ILOG("Descended into %c%c%c%c", id, id>>8, id>>16, id>>24);
|
||||
#endif
|
||||
return true;
|
||||
} else {
|
||||
#ifndef DEMO_VERSION //if this is missing.. heheh
|
||||
//write a chunk id, and prepare for filling in length later
|
||||
writeInt(id);
|
||||
writeInt(0); //will be filled in by Ascend
|
||||
stack[numLevels].startLocation=pos;
|
||||
numLevels++;
|
||||
return true;
|
||||
#else
|
||||
return true;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
void ChunkFile::seekTo(int _pos) {
|
||||
if (!fastMode) {
|
||||
fseek(file, 0, SEEK_SET);
|
||||
}
|
||||
pos = _pos;
|
||||
}
|
||||
|
||||
//let's ascend out
|
||||
void ChunkFile::ascend() {
|
||||
if (read) {
|
||||
//ascend, and restore information
|
||||
numLevels--;
|
||||
seekTo(stack[numLevels].parentStartLocation);
|
||||
eof = stack[numLevels].parentEOF;
|
||||
#ifdef CHUNKDEBUG
|
||||
int id = stack[numLevels].ID;
|
||||
ILOG("Ascended out of %c%c%c%c", id, id>>8, id>>16, id>>24);
|
||||
#endif
|
||||
if (id == intoId) {
|
||||
stack[depth_].ID = intoId;
|
||||
stack[depth_].length = length;
|
||||
stack[depth_].startLocation = startLocation;
|
||||
found = true;
|
||||
break;
|
||||
} else {
|
||||
numLevels--;
|
||||
//now fill in the written length automatically
|
||||
int posNow = pos;
|
||||
seekTo(stack[numLevels].startLocation - 4);
|
||||
writeInt(posNow-stack[numLevels].startLocation);
|
||||
seekTo(posNow);
|
||||
}
|
||||
}
|
||||
|
||||
//read a block
|
||||
void ChunkFile::readData(void *what, int count) {
|
||||
if (fastMode) {
|
||||
memcpy(what, data + pos, count);
|
||||
} else {
|
||||
if (fread(what, 1, count, file) != (size_t)count) {
|
||||
ELOG("Failed to read complete %d bytes", count);
|
||||
}
|
||||
}
|
||||
|
||||
pos+=count;
|
||||
count &= 3;
|
||||
if (count) {
|
||||
count=4-count;
|
||||
if (!fastMode) {
|
||||
if (fseek(file, count, SEEK_CUR) != 0) {
|
||||
ELOG("Missing padding");
|
||||
if (length > 0) {
|
||||
pos_ += length; // try next block
|
||||
} else {
|
||||
ERROR_LOG(SYSTEM, "Bad data in RIFF file : block length %d. Not descending.", length);
|
||||
pos_ = stack[depth_].parentStartLocation;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
pos+=count;
|
||||
}
|
||||
|
||||
// if we found nothing, return false so the caller can skip this
|
||||
if (!found) {
|
||||
pos_ = stack[depth_].parentStartLocation;
|
||||
return false;
|
||||
}
|
||||
|
||||
// descend into it
|
||||
// pos was set inside the loop above
|
||||
eof_ = stack[depth_].startLocation + stack[depth_].length;
|
||||
depth_++;
|
||||
return true;
|
||||
}
|
||||
|
||||
// let's ascend out
|
||||
void RIFFReader::Ascend() {
|
||||
// ascend, and restore information
|
||||
depth_--;
|
||||
pos_ = stack[depth_].parentStartLocation;
|
||||
eof_ = stack[depth_].parentEOF;
|
||||
}
|
||||
|
||||
// read a block
|
||||
void RIFFReader::ReadData(void *what, int count) {
|
||||
memcpy(what, data_ + pos_, count);
|
||||
pos_ += count;
|
||||
count &= 3;
|
||||
if (count) {
|
||||
count = 4 - count;
|
||||
pos_ += count;
|
||||
}
|
||||
}
|
||||
|
||||
//write a block
|
||||
void ChunkFile::writeData(const void *what, int count) {
|
||||
fwrite(what, 1, count, file);
|
||||
pos+=count;
|
||||
char temp[5]={0,0,0,0,0};
|
||||
count &= 3;
|
||||
if (count)
|
||||
{
|
||||
count=4-count;
|
||||
fwrite(temp, 1, count, file);
|
||||
pos+=count;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
void ChunkFile::writeWString(String str) {
|
||||
wchar_t *text;
|
||||
int len=str.length();
|
||||
#ifdef UNICODE
|
||||
#error
|
||||
text = str.getPointer();
|
||||
#else
|
||||
text = new wchar_t[len+1];
|
||||
str.toUnicode(text);
|
||||
#endif
|
||||
writeInt(len);
|
||||
writeData((char *)text, len * sizeof(wchar_t));
|
||||
#ifndef UNICODE
|
||||
delete [] text;
|
||||
#endif
|
||||
}
|
||||
*/
|
||||
|
||||
// Takes utf-8
|
||||
void ChunkFile::writeWString(const std::string &str) {
|
||||
unsigned short *text;
|
||||
int len = (int)str.length();
|
||||
text = new unsigned short[len+1];
|
||||
for (int i = 0; i < len; i++)
|
||||
text[i] = str[i];
|
||||
text[len]=0;
|
||||
writeInt(len);
|
||||
writeData((char *)text, len * sizeof(unsigned short));
|
||||
delete [] text;
|
||||
}
|
||||
|
||||
static void toUnicode(const std::string &str, uint16_t *t) {
|
||||
for (size_t i = 0; i < str.size(); i++) {
|
||||
*t++ = str[i];
|
||||
}
|
||||
*t++ = '\0';
|
||||
}
|
||||
|
||||
static std::string fromUnicode(const uint16_t *src, int len) {
|
||||
std::string str;
|
||||
str.resize(len);
|
||||
for (int i = 0; i < len; i++) {
|
||||
str[i] = src[i] > 255 ? ' ' : src[i];
|
||||
}
|
||||
return str;
|
||||
}
|
||||
|
||||
std::string ChunkFile::readWString() {
|
||||
int len=readInt();
|
||||
uint16_t *text = new uint16_t[len+1];
|
||||
readData((char *)text, len*sizeof(uint16_t));
|
||||
text[len] = 0;
|
||||
std::string temp = fromUnicode(text, len);
|
||||
delete [] text;
|
||||
return temp;
|
||||
}
|
||||
|
||||
void ChunkFile::writeString(const std::string &str) {
|
||||
uint16_t *text;
|
||||
int len = (int)str.size();
|
||||
text=new uint16_t[len+1];
|
||||
toUnicode(str, text);
|
||||
writeInt(len);
|
||||
writeData((char *)text,len*sizeof(uint16_t));
|
||||
delete [] text;
|
||||
}
|
||||
|
||||
std::string ChunkFile::readString() {
|
||||
int len=readInt();
|
||||
uint16_t *text = new uint16_t[len+1];
|
||||
readData((char *)text,len*sizeof(uint16_t));
|
||||
text[len]=0;
|
||||
std::string temp = fromUnicode(text, len);
|
||||
delete [] text;
|
||||
return temp;
|
||||
}
|
||||
int ChunkFile::getCurrentChunkSize() {
|
||||
if (numLevels)
|
||||
return stack[numLevels-1].length;
|
||||
int RIFFReader::GetCurrentChunkSize() {
|
||||
if (depth_)
|
||||
return stack[depth_ - 1].length;
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -10,62 +10,34 @@
|
||||
// otherwise the scheme breaks.
|
||||
|
||||
#include <string>
|
||||
#include <stdio.h>
|
||||
#include <cstdio>
|
||||
#include <cstdint>
|
||||
|
||||
#include "base/basictypes.h"
|
||||
|
||||
inline uint32_t flipID(uint32_t id) {
|
||||
return ((id>>24)&0xFF) | ((id>>8)&0xFF00) | ((id<<8)&0xFF0000) | ((id<<24)&0xFF000000);
|
||||
}
|
||||
|
||||
class ChunkFile {
|
||||
class RIFFReader {
|
||||
public:
|
||||
ChunkFile(const char *filename, bool _read);
|
||||
ChunkFile(const uint8_t *read_data, int data_size);
|
||||
RIFFReader(const uint8_t *data, int dataSize);
|
||||
~RIFFReader();
|
||||
|
||||
~ChunkFile();
|
||||
bool Descend(uint32_t id);
|
||||
void Ascend();
|
||||
|
||||
bool descend(uint32_t id);
|
||||
void ascend();
|
||||
int ReadInt();
|
||||
void ReadData(void *data, int count);
|
||||
|
||||
int readInt();
|
||||
void readInt(int &i) {i = readInt();}
|
||||
void readData(void *data, int count);
|
||||
// String readWString();
|
||||
std::string readWString();
|
||||
|
||||
void writeString(const std::string &str);
|
||||
std::string readString();
|
||||
|
||||
void writeInt(int i);
|
||||
//void writeWString(String str);
|
||||
void writeWString(const std::string &str);
|
||||
void writeData(const void *data, int count);
|
||||
|
||||
int getCurrentChunkSize();
|
||||
bool failed() const { return didFail; }
|
||||
std::string filename() const { return fn; }
|
||||
int GetCurrentChunkSize();
|
||||
|
||||
private:
|
||||
std::string fn;
|
||||
FILE *file;
|
||||
struct ChunkInfo {
|
||||
int startLocation;
|
||||
int parentStartLocation;
|
||||
int parentEOF;
|
||||
unsigned int ID;
|
||||
uint32_t ID;
|
||||
int length;
|
||||
};
|
||||
ChunkInfo stack[32];
|
||||
int numLevels;
|
||||
|
||||
uint8_t *data;
|
||||
int pos;
|
||||
int eof;
|
||||
bool fastMode;
|
||||
bool read;
|
||||
bool didFail;
|
||||
|
||||
void seekTo(int _pos);
|
||||
int getPos() const {return pos;}
|
||||
uint8_t *data_;
|
||||
int pos_ = 0;
|
||||
int eof_ = 0; // really end of current block
|
||||
int depth_ = 0;
|
||||
int fileSize_ = 0;
|
||||
};
|
||||
Reference in new issue
Block a user