您的位置:首页 > 其它

Embedding data into JPEG

2014-05-08 22:36 316 查看
/**

* segmentset.cpp

*

* Created on Apr 17, 2014

* Author: jiejing shan

*/

#include "segmentset.h"

#include "Log4Android.h"

#include "jpeg.h"

#define TAG "segmentset"

using namespace std;

bool SegmentSet::format(const char* data, const int dataLen, JPEG_MARKER marker, string segmentName)

{

if (data == NULL || dataLen == 0) {

return false;

}

if (!this->mmSet.empty()) {

this->mmSet.clear();

this->miSegmentNum = 0;

}

if (this->mpcBuff != NULL) {

delete [] this->mpcBuff;

this->mpcBuff = NULL;

}

int maxDataLen = Segment::getSegmentDataMaxLength(segmentName.size());

LOGE(TAG, "segment name length = %d, maxDataLen = %d\n", segmentName.size(), maxDataLen);

// chunks number

int totalNumber = (dataLen + (maxDataLen - 1)) / maxDataLen;

LOGE(TAG, "total number is %d\n", totalNumber);

int lastSegmentDataLen = dataLen % maxDataLen;

int buffSize = Segment::MAX_BYTES_SEGMENT * (totalNumber - 1)

+ lastSegmentDataLen

+ Segment::getSegmentHeadLength(segmentName.size());

LOGE(TAG, "buff size is %d\n", buffSize);

this->mpcBuff = new char[buffSize];

if (this->mpcBuff == NULL) {

return false;

}

this->miBuffLen = buffSize;

this->mJpegMarker = marker;

this->msSegmentName = segmentName;

int iFormatDataLen = maxDataLen;

const char* pcFormatData = data;

bool ret = true;

int i = 0;

for(i = 0; i < totalNumber; i ++) {

if (i == (totalNumber - 1)) {

iFormatDataLen = lastSegmentDataLen;

}

pcFormatData = data + i * maxDataLen;

Segment *pseg = new Segment(marker, segmentName);

if (pseg == NULL) {

break;

}

ret = pseg->formatSegment(this->mpcBuff + (i * Segment::MAX_BYTES_SEGMENT), pcFormatData, iFormatDataLen, i + 1, totalNumber);

if (!ret) {

delete pseg;

break;

}

this->mmSet.push_back(*pseg);

}

if ((i != totalNumber) || !ret) {

this->mmSet.clear();

delete [] this->mpcBuff;

this->mpcBuff = NULL;

return false;

}

this->miSegmentNum = totalNumber;

return true;

}

int SegmentSet::getSegmentByIndex(const int index, Segment& ret)

{

if ((index < 0) || (index >= this->miSegmentNum)) {

return -1;

}

list<Segment>::iterator it;

int i = 0;

for (it = this->mmSet.begin(); it != this->mmSet.end(); it ++) {

if (i == index) {

ret = *it;

return 0;

}

}

return -1;

}

bool SegmentSet::addSegmentSet(const SegmentSet other)

{

//I don't know why this method can't be called.

//this->mmSet.merge(other.mmSet);

this->miSegmentNum += other.miSegmentNum;

}

/**

* @brief checkSegmentHead

* parse the file stream, and get the segment head, if the head's every

* fields is valid, return them by the out put parameters, or , if the

* return isn't 0, it means the head is invalid.

* after checked, the file stream's read position must be as the same as before.

*

* @param is

* @param tag

* @param len

* @param segmentName

* @param chunkNum

* @param maxChunkNum

*

* @return 0, successful

* -1, tag is not 0xFFE3.

* -2, the head length, the chunk number or the max chunk number is invalid.

* -3, the segment name of file isn't the same segment name;

*/

int SegmentSet::checkSegmentHead(ifstream& is, unsigned short& tag, int& len, string& segmentName, int& chunkNum, int& maxChunkNum) {

char buff[2] = "\0";

unsigned short tmpTag = 0;

int tmpLen = 0;

char segName[64] = "\0";

int segNameLen = 0;

int tmpChunkNum = 0;

int tmpMaxChunkNum = 0;

is.read(buff, 2);

tmpTag = ((unsigned short)buff[0] << 8) | (unsigned short)buff[1];

if (tmpTag != Jpeg::DEPTH_APP_SEG) {

is.seekg(-2, ios::cur);

return -1;

}

is.read(buff, 2);

//tmpLen = ((unsigned short)buff[0] << 8) | (unsigned short)buff[1];

tmpLen = ((unsigned char)buff[0] << 8) | (unsigned char)buff[1];

LOGE(TAG, "checkSegmentHead: tmpLen %d", tmpLen);

if (tmpLen > Segment::MAX_BYTES_SEGMENT ||

tmpLen < 0) {

is.seekg(-4, ios::cur);

return -2;

}

do {

is.read(buff, 1);

segName[segNameLen ++] = buff[0];

} while(buff[0] != '\0');

LOGE(TAG, "segment name len is %d, head len is %d\n", segNameLen, Segment::getSegmentHeadLength(segNameLen - 1));

if (segmentName.size() != 0 &&

(0 != strcmp(segmentName.c_str(), segName))) {

is.seekg((0 - segNameLen - 4), ios::cur);

return -3;

}

is.read(buff, 2);

tmpChunkNum = (unsigned char)buff[0];

tmpMaxChunkNum = (unsigned char)buff[1];

if ((tmpChunkNum < 1) ||

(tmpMaxChunkNum < 1) ||

(tmpChunkNum > tmpMaxChunkNum))

{

is.seekg((0 - (Segment::getSegmentHeadLength(segNameLen - 1))), ios::cur);

return -2;

}

if (tmpMaxChunkNum > 1) {

if (tmpChunkNum != tmpMaxChunkNum &&

tmpLen != Segment::MAX_BYTES_SEGMENT - 2) {

is.seekg((0 - (Segment::getSegmentHeadLength(segNameLen -1))), ios::cur);

return -2;

}

}

is.seekg((0 - (Segment::getSegmentHeadLength(segNameLen -1))), ios::cur);

tag = tmpTag;

len = tmpLen;

segmentName = segName;

chunkNum = tmpChunkNum;

maxChunkNum = tmpMaxChunkNum;

return 0;

}

int SegmentSet::parse(ifstream& is)

{

if (is.fail()) {

LOGE(TAG, "file stream is fail!");

return -1;

}

unsigned short tag = 0;

int len = 0;

string segmentName;

int chunkNum = 0;

int maxChunkNum = 0;

int maxSegSetLen = 0;

int ret = 0;

if (this->mpcBuff != NULL) {

this->release();

}

do {

ret = checkSegmentHead(is, tag, len, segmentName, chunkNum, maxChunkNum);

if (ret < 0) {

LOGE(TAG, "check segment head error");

break;

}

LOGI(TAG, "read a segment head ret = %d, tag is %x, len is %x, segment name is %s, chunk num is %d, max chunk number is %d\n",

ret, tag, len, segmentName.c_str(), chunkNum, maxChunkNum);

is.seekg(len + 2, ios::cur);

maxSegSetLen += len + 2;

if (chunkNum == maxChunkNum)

break;

} while(1);

if (ret < 0) {

return -1;

}

this->mpcBuff = new char[maxSegSetLen];

if (this->mpcBuff == NULL) {

LOGE(TAG, "not enough memory");

return -1;

}

is.seekg((0 - maxSegSetLen), ios::cur);

is.read(this->mpcBuff, maxSegSetLen);

this->miBuffLen = maxSegSetLen;

this->mJpegMarker = (JPEG_MARKER)tag;

this->msSegmentName = segmentName;

for (int i = 1; i <= maxChunkNum; i ++) {

Segment seg((JPEG_MARKER)tag, segmentName);

seg.parse(this->mpcBuff + ((i - 1) * Segment::MAX_BYTES_SEGMENT));

this->mmSet.push_back(seg);

}

this->miSegmentNum = maxChunkNum;

LOGE(TAG , "leave segment set parse");

return ret;

}

int SegmentSet::getDataLength() const

{

int allDataLen = 0;

LOGE(TAG, "segment size is %d", this->mmSet.size());

for(list<Segment>::const_iterator it = this->mmSet.begin(); it != this->mmSet.end(); it++)

{

LOGE(TAG, "segment data len is %ud\n", it->getSegmentDataLength());

allDataLen += it->getSegmentDataLength();

}

return allDataLen;

}

/*

* user will ensure the pcData buff have enough memory.

*/

int SegmentSet::getData(const char* pcData) const

{

if (pcData == NULL) {

return -1;

}

const char* pcTmp = pcData;

for(list<Segment>::const_iterator it = this->mmSet.begin(); it != this->mmSet.end(); it++)

{

memcpy((void*)pcTmp, it->getSegmentData(), it->getSegmentDataLength());

pcTmp += it->getSegmentDataLength();

}

return 0;

}

/**

* segment.cpp

*

* Created on Apr 17, 2014

* Author : jiejing shan

*/

#include "segment.h"

#include <string>

#include "../library/Log4Android.h"

using namespace std;

#define TAG "segment"

const int Segment::MAX_BYTES_SEGMENT = 65535;

int Segment::getSegmentDataMaxLength(const int segNameLen)

{

//2 bytes APP MAKER, 2 bytes TAG LENGTH, 1 byte chunk number, 1 byte max chunk number, segment name length and '\0'

int iSegmentHeadLen = segNameLen + 1 + 6;

return MAX_BYTES_SEGMENT - iSegmentHeadLen;

}

int Segment::getSegmentDataLength() const

{

return this->miDataLen;

}

int Segment::getSegmentLength()

{

//data length, segment name length and '\0', 2 bytes TAG length, 1 bytes chunk number, 1 bytes max chunk number

return this->miDataLen + this->msSegmentName.size() + 1 + 4;

}

char* Segment::getSegmentData() const

{

return this->mpcStart + getSegmentHeadLength(this->msSegmentName.size());

}

string Segment::getSegmentName()

{

return this->msSegmentName;

}

JPEG_MARKER Segment::getSegmentMarker()

{

return this->mMarker;

}

int Segment::getSegmentHeadLength(const int segNameLen)

{

return segNameLen + 1 + 6;

}

/*

* formatSegment

* according to the data, chunk number and max chunk number, format the segment buffer

* the pcBuff must be had enough memory to contain segment head and data.

*/

bool Segment::formatSegment(char* pcBuff, const char* data, const int dataLen, const int chunkNum, const int maxChunkNum)

{

if (pcBuff == NULL) {

return false;

}

memset(pcBuff, 0, getSegmentHeadLength(this->msSegmentName.size()) + dataLen);

this->mpcStart = pcBuff;

this->miDataLen = dataLen;

this->miChunkNum = chunkNum;

this->miMaxChunkNum = maxChunkNum;

char* pTmp = this->mpcStart;

int len = getSegmentLength();

*pTmp = (char)((((int)this->mMarker) & 0xFF00) >> 8);

pTmp ++;

*pTmp = (char)(((int)this->mMarker) & 0x00FF);

pTmp ++;

*pTmp = (char) ((len & 0xFF00) >> 8);

pTmp ++;

*pTmp = (char) (len & 0x00FF);

pTmp ++;

memcpy(pTmp, this->msSegmentName.c_str(), this->msSegmentName.size());

pTmp += this->msSegmentName.size() + 1;

*pTmp = (char) (chunkNum & 0x00FF);

pTmp ++;

*pTmp = (char) (maxChunkNum & 0xFF);

pTmp ++;

memcpy(pTmp, data, dataLen);

return true;

}

/*

* init

* according a segment buffer, construct a segment class

* uncompleted.

*/

Segment Segment::init(char* buff)

{

char name[64] = "\0";

char* pTmp = buff;

int marker = (pTmp[0] << 8) + pTmp[1];

pTmp += 2;

int segLen = (pTmp[0] << 8) + pTmp[1];

pTmp += 2;

strcpy(name, pTmp);

int nameLen = strlen(name);

pTmp += nameLen + 1;

int chunkNum = pTmp[0];

pTmp ++;

int maxChunkNum = pTmp[0];

pTmp ++;

//Segment *pSegment = new Segment((JPG_APP_MARKER)marker, name);

//pSegment->mpcBuffer

}

int Segment::parse(char* buff)

{

const char* pcTmp = buff;

this->mpcStart = buff;

pcTmp += 2;

int len = ((unsigned char)pcTmp[0] << 8) | (unsigned char)pcTmp[1];

//int len = ((unsigned short)pcTmp[0] << 8) | (unsigned short)pcTmp[1];

LOGE(TAG, "parse len is %d\n", len);

pcTmp += 2;

this->miDataLen = len - this->msSegmentName.size() - 1 - 4;

LOGE(TAG, "data len is %d\n", this->miDataLen);

pcTmp += this->msSegmentName.size() + 1;

this->miChunkNum = (unsigned char)pcTmp[0];

this->miMaxChunkNum = (unsigned char)pcTmp[1];

}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: