#include "ogg.h" #include #include #include #include #define lsb32(offset) data[offset] | data[offset+1] << 8 | data[offset+2] << 16 | data[offset+3] << 24 namespace OGG{ Page::Page(){ data = NULL; datasize = 0; dataSum = 0; } bool Page::read(std::string & newData){ dataSum = 0; //datasize = 0; if (newData.size()<27){ return false; } if (!checkDataSize(27)){ return false; } memcpy(data, newData.c_str(), 27);//copying the header, always 27 bytes if(!checkDataSize(27 + getPageSegments())){ return false; } memcpy(data + 27, newData.c_str() + 27, getPageSegments()); //copying the first part of the page into data, which tells the size of the page for(unsigned int i = 0; i < getPageSegments(); i++){ dataSum += getSegmentTable()[i]; } if(!checkDataSize(27 + getPageSegments()+dataSum)){ return false; } memcpy(data + 27 + getPageSegments(), newData.c_str() + 27 + getPageSegments(), dataSum); newData.erase(0, getPageSize()); return true; } long unsigned int Page::getMagicNumber(){ return ntohl(((long unsigned int*)(data))[0]); } void Page::setMagicNumber(){ if(checkDataSize(4)){ memcpy(data, "OggS", 4); } } char Page::getVersion(){ return data[4]; } void Page::setVersion(char newVal){ if(checkDataSize(5)){ data[4] = newVal; } } char Page::getHeaderType(){ return data[5]; } void Page::setHeaderType(char newVal){ if(checkDataSize(6)){ data[5] = newVal; } } long long unsigned int Page::getGranulePosition(){ if(checkDataSize(14)){ //switching bit order upon return return ntohl(((long unsigned*)(data+6))[1]) & ((long long unsigned)(ntohl(((long unsigned*)(data+6))[0]) << 32)); } return 0; } void Page::setGranulePosition(long long unsigned int newVal){ if(checkDataSize(14)){ ((long unsigned*)(data+6))[1] = htonl(newVal & 0xFFFFFFFF); ((long unsigned*)(data+6))[0] = htonl((newVal >> 32) & 0xFFFFFFFF); } } long unsigned int Page::getBitstreamSerialNumber(){ //return ntohl(((long unsigned int*)(data+14))[0]); return lsb32(14); } void Page::setBitstreamSerialNumber(long unsigned int newVal){ if(checkDataSize(18)){ ((long unsigned *)(data+14))[0] = htonl(newVal); } } long unsigned int Page::getPageSequenceNumber(){ return lsb32(18); } void Page::setPageSequenceNumber(long unsigned int newVal){ if(checkDataSize(22)){ ((long unsigned *)(data+18))[0] = htonl(newVal); } } long unsigned int Page::getCRCChecksum(){ return ntohl(((long unsigned int*)(data+22))[0]); //return lsb32(22); } void Page::setCRCChecksum(long unsigned int newVal){ if(checkDataSize(26)){ ((long unsigned *)(data+22))[0] = htonl(newVal); } } char Page::getPageSegments(){ return data[26]; } inline void Page::setPageSegments(char newVal){ data[26] = newVal; } char* Page::getSegmentTable(){ return data+27; } std::deque Page::getSegmentTableDeque(){ std::deque retVal; unsigned int temp = 0; char* segmentTable = getSegmentTable(); for (unsigned int i = 0; i < getPageSegments(); i++){ temp += segmentTable[i]; if (segmentTable[i] < 255){ retVal.push_back(temp); temp = 0; } } return retVal; } bool Page::setSegmentTable(std::vector layout){ unsigned int place = 0; char table[255]; for (unsigned int i = 0; i < layout.size(); i++){ while (layout[i]>=255){ if (place >= 255) return false; table[place] = 255; layout[i] -= 255; place++; } if (place >= 255) return false; table[place] = layout[i]; place++; } setSegmentTable(table,place); return true; } void Page::setSegmentTable(char* newVal, unsigned int length){ if(checkDataSize(27 + length)){ memcpy(data + 27, newVal, length); } } unsigned long int Page::getPageSize(){ return 27 + getPageSegments()+dataSum; } char* Page::getFullPayload(){ return data + 27 + getPageSegments(); } std::string Page::toPrettyString(){ std::stringstream r; r << "Size(" << getPageSize() << ")(" << dataSum << ")" << std::endl; r << "Magic_Number: " << std::string(data, 4) << std::endl; r << "Version: " << (int)getVersion() << std::endl; r << "Header_type: " << std::hex << (int)getHeaderType() << std::dec; if (getHeaderType() & 0x01){ r << " continued"; } if (getHeaderType() & 0x02){ r << " bos"; } if (getHeaderType() & 0x04){ r << " eos"; } r << std::endl; r << "Granule_position: " << getGranulePosition() << std::endl; r << "Bitstream_SN: " << getBitstreamSerialNumber() << std::endl; r << "Page_sequence_number: " << getPageSequenceNumber() << std::endl; r << "CRC_checksum: " << std::hex << getCRCChecksum()<< std::dec << std::endl; r << " Calced Checksum: " << std::hex << calcChecksum() << std::dec << std::endl; r << "CRC_checksum write: " << std::hex << getCRCChecksum()<< std::dec << std::endl; r << "Page_segments: " << (int)getPageSegments() << std::endl; r << "SegmentTable: "; std::deque temp = getSegmentTableDeque(); for (std::deque::iterator i = temp.begin(); i != temp.end(); i++){ r << (*i) << " "; } r << std::endl; return r.str(); } long unsigned int Compute(char* buffer, unsigned int count){ long unsigned int m_crc = ~0u; //const unsigned char* ptr = (const unsigned char *) buffer; for (unsigned int i = 0; i < count; i++) { buffer++; m_crc ^= ((unsigned long int)buffer << 24); for (int i = 0; i < 8; i++) { if (m_crc & 0x80000000) { m_crc = (m_crc << 1) ^ 0x04C11DB7; }else { m_crc <<= 1; } } } return m_crc; } long unsigned int Page::calcChecksum(){ long unsigned int retVal = 0; long unsigned int oldChecksum = getCRCChecksum(); setCRCChecksum (0); retVal = Compute(data, getPageSize()); setCRCChecksum (oldChecksum); return retVal; } bool Page::checkDataSize(unsigned int size){ if (size > datasize){ void* tmp = realloc(data,size); if (tmp){ data = (char*)tmp; datasize = size; return true; }else{ return false; } }else{ return true; } } }