www.pudn.com > mysee.zip > ZZLFileWriter.cpp


/* 
*  Openmysee 
* 
*  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 "stdafx.h" 
#include "zzlfilewriter.h" 
#include "md5.h" 
 
ZZLFileWriter::ZZLFileWriter(void) : FILE_VERSION(1.0f),mbIsSingleAudio(FALSE) 
{ 
	zzlHandle = INVALID_HANDLE_VALUE; 
	blockCount = 0; 
	dataOffset = 0; 
	startTime = endTime = 0; 
 
	dataHandle = keySampleHandle = configHandle = INVALID_HANDLE_VALUE; 
	firstSampleTime = firstKeySampleTime = 0; 
	newBlockSize = 0; 
	sampleBuffer = NULL; 
	sampleBufferSize = 0; 
	dataFileCount = 0; 
	audioDataSize = videoDataSize = 0; 
	audioStartTime = audioEndTime = videoStartTime = videoEndTime = 0; 
 
	mLLMaxAudioTime = 0; 
	mLLMaxVideoTime = 0; 
 
	InitializeCriticalSection(&zzlfile_cs); 
} 
 
ZZLFileWriter::~ZZLFileWriter(void) 
{ 
	CloseHandle(zzlHandle); 
	CloseHandle(dataHandle); 
	CloseHandle(keySampleHandle); 
	CloseHandle(configHandle); 
	zzlHandle= dataHandle = keySampleHandle = configHandle = INVALID_HANDLE_VALUE; 
	SAFE_ARRAYDELETE(sampleBuffer); 
	DeleteCriticalSection(&zzlfile_cs); 
} 
 
bool ZZLFileWriter::Init(string path, string name) { 
	if(path.empty() || name.empty()) 
		return false; 
	if(!chnlName.empty()) 
		return true;	 
	 
	//补路径后的斜杠 
	string::const_iterator litSavePath = path.end(); 
	--litSavePath; 
	if ('\\' != static_cast(*litSavePath)) 
	{ 
		path += "\\";  
	} 
 
	savePath = path+name; // 再加一层目录,名字就是节目名 
	chnlName = name; 
 
	// calculate md5 hashcode of channel name 
	char* md5Str = NULL; 
	MD5 md5(reinterpret_cast(chnlName.data()), chnlName.size()); 
	md5Str = md5.hex_digest(); 
	assert(md5Str); 
 
	// 删除旧的临时文件 
	if(!RemoveOldTmpFile(savePath)) { 
		return false;	// 不能删除旧的节目数据,此次压缩取消 
	} 
 
	for(;;) { 
		string bufferFileName = savePath+"\\"+name+".zzl"; 
		// 创建zzl文件 
		if((zzlHandle = CreateFile(bufferFileName.data(),  
			GENERIC_WRITE | GENERIC_READ,  
			FILE_SHARE_READ,  
			NULL,  
			CREATE_ALWAYS,  
			FILE_ATTRIBUTE_NORMAL,  
			NULL)) == INVALID_HANDLE_VALUE) 
		{ 
			int err = GetLastError(); 
			if(err == ERROR_PATH_NOT_FOUND) {  
				// 创建文件失败,因为有不存在的中间目录,需要首先创建中间目录 
				int index = 0; 
				string temp; 
				do { 
					int offset = bufferFileName.find_first_of('\\', index); 
					if(offset == -1) 
						break; 
					temp = bufferFileName.substr(0, offset); 
					index = offset+1; 
					if(!CreateDirectory(temp.data(), NULL)) { 
						int ret = GetLastError(); 
						if(ret == ERROR_ALREADY_EXISTS || ret == ERROR_ACCESS_DENIED) 
							continue; 
						break; 
					} 
				} 
				while(1); 
				// Create Again 
				continue; 
			} 
			else 
				return false; 
		} 
		break; // succeeded 
	} 
 
	DWORD writenBytes = 0; 
 
	// 1. write ZZLD 
	char fcc[5]; 
	strcpy(fcc, "ZZLD"); 
	if(INVALID_SET_FILE_POINTER == SetFilePointer(zzlHandle, 0, 0, FILE_BEGIN)) 
		return false; 
	if(!WriteFile(zzlHandle, fcc, 4, &writenBytes, NULL)) 
		return false; 
	if(writenBytes != 4) 
		return false; 
 
	// 2. write file version 
	float version = FILE_VERSION; 
	if(!WriteFile(zzlHandle, &version, sizeof(version), &writenBytes, NULL)) 
		return false; 
	if(writenBytes != sizeof(version)) 
		return false; 
 
	savePath = savePath + "\\" + md5Str; 
 
	if(!CreateDirectory(savePath.data(), NULL)) { 
		int ret = GetLastError(); 
		if(ret != ERROR_ALREADY_EXISTS && ret != ERROR_ACCESS_DENIED) 
		{ 
			return false; 
		}		 
	} 
 
	keySampleHandle = CreateFile((savePath+"\\keysample").data(),  
			GENERIC_WRITE | GENERIC_READ,  
			FILE_SHARE_READ,  
			NULL,  
			CREATE_ALWAYS,  
			FILE_ATTRIBUTE_NORMAL,  
			NULL); 
 
 
	if(keySampleHandle == INVALID_HANDLE_VALUE) 
		return false; 
 
	configHandle = CreateFile((savePath+"\\config").data(),  
			GENERIC_WRITE | GENERIC_READ,  
			FILE_SHARE_READ,  
			NULL,  
			CREATE_ALWAYS,  
			FILE_ATTRIBUTE_NORMAL,  
			NULL); 
	if(configHandle == INVALID_HANDLE_VALUE) 
		return false; 
 
	char temp[16]; 
	itoa(dataFileCount, temp, 10); 
	dataHandle = CreateFile((savePath+"\\"+temp).data(),  
			GENERIC_WRITE | GENERIC_READ,  
			FILE_SHARE_READ,  
			NULL,  
			CREATE_ALWAYS,  
			FILE_ATTRIBUTE_NORMAL,  
			NULL); 
	if(dataHandle == INVALID_HANDLE_VALUE) 
		return false; 
 
	mLLMaxAudioTime = 0; 
	mLLMaxVideoTime = 0; 
 
	// 写入节目开始的标志Sample 
	SampleHeader header; 
	memset(&header, 0, sizeof(SampleHeader)); 
	header.size = sizeof(SampleHeader); 
	header.length = 0xffffffff; 
	header.start = 0xffffffffffffffff; 
	header.bSyncPoint = 1; 
	if(!PutSample(header, NULL)) 
		return false; 
 
	return true; 
} 
 
bool ZZLFileWriter::SetMediaType(const TVMEDIATYPESECTION& audioType, BYTE* audioData, const TVMEDIATYPESECTION& videoType, BYTE* videoData) { 
	if(zzlHandle == INVALID_HANDLE_VALUE) 
		return false; 
	assert(audioData || videoData); 
	DWORD writenBytes = 0; 
 
	char temp[1024]; 
	memset(temp, 0, sizeof(temp)); 
 
	char* pTemp = temp; 
	// write media type 
	memcpy(pTemp, &videoType, sizeof(videoType)); 
	pTemp += sizeof(videoType); 
	if(videoData) 
		memcpy(pTemp, videoData, videoType.cbFormat); 
	pTemp += videoType.cbFormat; 
	memcpy(pTemp, &audioType, sizeof(audioType)); 
	pTemp += sizeof(audioType); 
	if(audioData) 
		memcpy(pTemp, audioData, audioType.cbFormat); 
	pTemp += audioType.cbFormat; 
	// write start & end Time 
	memcpy(pTemp, &startTime, sizeof(startTime)); 
	pTemp += sizeof(startTime); 
	memcpy(pTemp, &endTime, sizeof(endTime)); 
	pTemp += sizeof(endTime); 
 
	if(INVALID_SET_FILE_POINTER == SetFilePointer(zzlHandle, 4+sizeof(float), 0, FILE_BEGIN)) 
		return false; 
	if(!WriteFile(zzlHandle, temp, pTemp-temp, &writenBytes, NULL)) 
		return false; 
	if(writenBytes != pTemp-temp) 
		return false; 
 
	dataOffset = 4 + sizeof(float) + pTemp-temp; 
 
	// calculate md5 hashcode of channel name 
	char* md5Str = NULL; 
	MD5 md5(reinterpret_cast(chnlName.data()), chnlName.size()); 
	md5Str = md5.hex_digest(); 
	assert(md5Str); 
 
	char cfgStr[1024]; 
	memset(cfgStr, 0, sizeof(cfgStr)); 
	// write config data 
	// 注意:此处给BitRate所留的空间是“BitRate=000000000” 
	sprintf(cfgStr, "BitRate=000000000\nBlockSize=%d\nChannelName=%s\nResourceHash=%s\nDataLength=%d\nData=",  
		BLOCK_SIZE, chnlName.data(), md5Str,  
		sizeof(audioType) + audioType.cbFormat + sizeof(videoType) + videoType.cbFormat); 
	delete [] md5Str; 
 
	int totalLen = strlen(cfgStr); 
	// write media type 
	memcpy(cfgStr+totalLen, temp, sizeof(videoType)+videoType.cbFormat+sizeof(audioType)+audioType.cbFormat); 
	totalLen += sizeof(videoType)+videoType.cbFormat+sizeof(audioType)+audioType.cbFormat; 
 
	if(INVALID_SET_FILE_POINTER == SetFilePointer(configHandle, 0, 0, FILE_BEGIN)) 
		return false; 
	if(!WriteFile(configHandle, cfgStr, totalLen, &writenBytes, NULL)) 
		return false; 
	if(writenBytes != totalLen) 
		return false; 
 
	return true; 
} 
 
/* 
 *	block content 
 *  |offset of first keysample(int32)|offset of first sample(int32)|list of samples|last uncomplete sample| 
 *  |sample data| = |header(SampleHeader)|data(...)| 
 */ 
bool ZZLFileWriter::SaveSample(UINT dataOff, const UINT allSize) { 
	// at the start of new block, write the offset of next sample 
	if(newBlockSize == 0) { 
		// 在开头的4个字节写入first keysample offset 
		*(UINT*)newBlock = 0;	// 默认值是0 
		// 在此后的4个字节写入first sample offset 
		*((UINT*)newBlock+1) = sizeof(int)*2;		// 如果开始保存新的Sample,则first sample offset = 8 
		if(dataOff > 0) 
			*((UINT*)newBlock+1) += allSize-dataOff;// 如果保存前一个sample剩下的部分,则要加上其剩下的长度 
		if(*((UINT*)newBlock+1) >= BLOCK_SIZE)		// 如果此sample剩下的部分长度超过当前Block,则用UINT_MAX表示 
			*((UINT*)newBlock+1) = UINT_MAX; 
 
		newBlockSize += sizeof(int)*2; 
	} 
 
	if(	*(UINT*)(newBlock) == 0 &&		// 当前Block尚未记录FirstKeySampleOffset 
		dataOff == 0 &&					// 一个新的Sample 
		firstKeySampleTime &&			// KeySample的时间 
		newBlockSize+sizeof(SampleHeader) < BLOCK_SIZE) // SampleHeader刚好保存在当前Block中 
	{ 
		// 在开头的4个字节记录FirstKeySampleOffset, sizeof(UINT)*2是start在SampleHeader中的位置 
		*(UINT*)(newBlock) = newBlockSize+sizeof(UINT)*2; 
	} 
 
	// 比较剩余数据与剩余空间 
	if(allSize-dataOff >= BLOCK_SIZE-newBlockSize) { 
		// 剩余数据超过剩余空间,则填满并保存当前Block,并继续存储剩下的数据 
		memcpy(newBlock+newBlockSize, sampleBuffer+dataOff, BLOCK_SIZE-newBlockSize); 
		dataOff += BLOCK_SIZE-newBlockSize; 
 
		newBlockSize = 0;	// 开始新的Block 
		// 保存旧的Block 
		if(!SaveBlock(newBlock, BLOCK_SIZE)) 
			return false; 
 
		// 继续保存剩余的数据 
		if(allSize-dataOff > 0) 
			return SaveSample(dataOff, allSize); 
	} 
	else { 
		// 剩余数据小于剩余空间,复制并等待下一个Sample 
		memcpy(newBlock+newBlockSize, sampleBuffer+dataOff, allSize-dataOff); 
		newBlockSize += allSize-dataOff; 
	} 
	return true; 
} 
 
bool ZZLFileWriter::PutSample(const SampleHeader& header, BYTE* pData) { 
	if(header.size > 1024*1024) 
		return false; 
	bool ret = true; 
	EnterCriticalSection(&zzlfile_cs); 
 
	char tmpStr[96]; 
	_i64toa(header.start, tmpStr, 10); 
	_i64toa(header.length+header.start, tmpStr+32, 10); 
	DbgLog((LOG_TRACE, 5, TEXT("start: %s end: %s"), tmpStr, tmpStr+32)); 
 
	// record first sample time 
	if(firstSampleTime == 0) 
		firstSampleTime = (time_t)(header.start/10000000); 
	// record first keysample time 
	 
	//区分单音频和视频的情况 
	if (firstKeySampleTime == 0 && TRUE == mbIsSingleAudio && header.start != 0xffffffffffffffff/*非节目起始标志Sample*/) 
	{ 
		firstKeySampleTime = (time_t)(header.start/10000000); 
	} 
	else if(firstKeySampleTime == 0 && header.bSyncPoint && header.start != 0xffffffffffffffff/*非节目起始标志Sample*/)  
	{ 
		firstKeySampleTime = (time_t)(header.start/10000000); 
	} 
 
	if(header.size > sampleBufferSize) { 
		SAFE_ARRAYDELETE(sampleBuffer); 
		sampleBuffer = new BYTE[header.size]; 
		sampleBufferSize = header.size; 
	} 
 
	// copy sample header into sample buffer 
	memcpy(sampleBuffer, &header, sizeof(SampleHeader)); 
 
	// copy sample data into sample buffer; 
	if(header.size-sizeof(SampleHeader)) { 
		assert(pData); 
		memcpy(sampleBuffer+sizeof(SampleHeader), pData, header.size-sizeof(SampleHeader)); 
	} 
	 
#ifndef GENERATE_SMALL_ZZL	 
	if(header.start > 0 && header.start != 0xffffffffffffffff/*非节目起始标志Sample*/) { 
		if(header.bAudioSample) { 
 
				 
			//检查音频时间是否回滚 
			if (header.start > mLLMaxAudioTime) 
			{ 
				mLLMaxAudioTime = header.start; 
			} 
			else 
			{ 
				//char lstr[1024]; 
				//sprintf(lstr, "这段音频的数据应该已经播放过了,不能进行直播%I64D",header.start); 
				 
				MessageBox(NULL,"这段音频的数据应该已经播放过了,不能进行直播", "错误", MB_OK|MB_ICONSTOP); 
				return FALSE; 
			} 
			 
			// calculate total size of audio samples 
			audioDataSize += header.size; 
			// set start&end time of audio samples 
			if(header.start > audioEndTime || header.start < audioStartTime) { 
				if(audioStartTime == 0 || header.start < audioStartTime) { 
					audioStartTime = header.start; 
				} 
				if(header.start+header.length > audioEndTime) 
					audioEndTime = header.start+header.length; 
			} 
			assert(audioStartTime <= header.start); 
		} 
		else { 
			 
			//检查视频时间是否回滚 
			if (header.start > mLLMaxVideoTime) 
			{ 
				mLLMaxVideoTime = header.start; 
			} 
			else 
			{ 
				MessageBox(NULL,"这段视频的数据应该已经播放过了,不能进行直播", "错误", MB_OK|MB_ICONSTOP); 
				return FALSE; 
			} 
			 
			// calculate total size of video samples 
			videoDataSize += header.size; 
			// set start&end time of video samples 
			if(header.start > videoEndTime || header.start < videoStartTime) { 
				if(videoStartTime == 0 || header.start < videoStartTime) { 
					videoStartTime = header.start; 
				} 
				if(header.start+header.length > videoEndTime) 
					videoEndTime = header.start+header.length; 
			} 
			assert(videoStartTime <= header.start); 
 
			// 检查video sample和audio sample是否时间相差过多,相差过多的节目不适合进行直播! 
			 
			if(videoEndTime > 0 && audioEndTime > 0) 
			{ 
				if(videoEndTime > audioEndTime+10*10000000 
					|| audioEndTime > videoEndTime+10*10000000) 
				{ 
					::MessageBox(NULL, 
						"现在视频和音频已经不同步,相差超过10s,这样压缩出来的节目是不能进行直播的!", 
						"错误", MB_OK|MB_ICONSTOP); 
					ret = false; 
				} 
			} 
			 
		} 
	} 
 
#endif 
 
	if(ret) 
		ret = SaveSample(0, header.size); 
	 
	LeaveCriticalSection(&zzlfile_cs); 
	 
	return ret; 
} 
 
bool ZZLFileWriter::SaveBlock(const PBYTE data, const UINT size) { 
	if(zzlHandle == INVALID_HANDLE_VALUE) 
		return false; 
	DWORD writenBytes = 0; 
	if(INVALID_SET_FILE_POINTER == SetFilePointer(zzlHandle, dataOffset + blockCount*BLOCK_SIZE, 0, FILE_BEGIN)) 
		return false; 
	if(!WriteFile(zzlHandle, data, size, &writenBytes, NULL)) 
		return false; 
	if(writenBytes != size) 
		return false; 
 
	// write min&max keySample to zzl file 
	if(firstSampleTime > 0) { 
		if(firstSampleTime > endTime || firstSampleTime < startTime) { 
			if(startTime == 0 || firstSampleTime < startTime) { 
				startTime = firstSampleTime; 
			} 
			if(firstSampleTime > endTime) 
				endTime = firstSampleTime; 
			if(INVALID_SET_FILE_POINTER == SetFilePointer(zzlHandle, dataOffset-sizeof(startTime)-sizeof(endTime), 0, FILE_BEGIN)) 
				return false; 
			// write start & end Time 
			if(!WriteFile(zzlHandle, &startTime, sizeof(startTime), &writenBytes, NULL)) 
				return false; 
			if(writenBytes != sizeof(startTime)) 
				return false; 
			if(!WriteFile(zzlHandle, &endTime, sizeof(endTime), &writenBytes, NULL)) 
				return false; 
			if(writenBytes != sizeof(endTime)) 
				return false; 
		} 
		assert(startTime <= firstSampleTime); 
	} 
 
	if(firstKeySampleTime > 0) { 
		// write keysample to keysample file 
		if(INVALID_SET_FILE_POINTER == SetFilePointer(keySampleHandle, 0, 0, FILE_END)) // seek to end of file 
			return false; 
		// write blockID 
		if(!WriteFile(keySampleHandle, &blockCount, sizeof(blockCount), &writenBytes, NULL)) 
			return false; 
		if(writenBytes != sizeof(blockCount)) 
			return false; 
		// write keysample 
		if(!WriteFile(keySampleHandle, &firstKeySampleTime, sizeof(firstKeySampleTime), &writenBytes, NULL)) 
			return false; 
		if(writenBytes != sizeof(firstKeySampleTime)) 
			return false; 
	} 
 
	// write block data to data file 
	if(blockCount/BLOCK_OF_DATA_FILE > dataFileCount) { 
		dataFileCount = blockCount/BLOCK_OF_DATA_FILE; 
		CloseHandle(dataHandle); 
		char temp[16]; 
		itoa(dataFileCount, temp, 10); 
		dataHandle = CreateFile((savePath+"\\"+temp).data(),  
				GENERIC_WRITE | GENERIC_READ,  
				FILE_SHARE_READ,  
				NULL,  
				CREATE_ALWAYS,  
				FILE_ATTRIBUTE_NORMAL,  
				NULL); 
		if(dataHandle == INVALID_HANDLE_VALUE) 
			return false; 
	} 
	if(INVALID_SET_FILE_POINTER == SetFilePointer(dataHandle, (blockCount%BLOCK_OF_DATA_FILE)*BLOCK_SIZE, 0, FILE_BEGIN)) 
		return false; 
	if(!WriteFile(dataHandle, data, size, &writenBytes, NULL)) 
		return false; 
	if(writenBytes != size) 
		return false; 
 
	firstKeySampleTime = 0; 
	firstSampleTime = 0; 
	blockCount++; 
 
	// 将最新的码率统计写入配置文件 
	if(!SaveBitRate()) 
		return false; 
	return true; 
} 
 
double ZZLFileWriter::GetBitRate() { 
	// 根据起始Sample和最近一个Sample的时间戳以及数据的大小,分别计算视频音频的码率,然后加起来就是总的码率 
	double bitRate = 0.0f; 
	if(videoEndTime-videoStartTime > 0) 
		bitRate += ((double)videoDataSize)/1024/((videoEndTime-videoStartTime)/10000000); 
	if(audioEndTime-audioStartTime > 0) 
		bitRate += ((double)audioDataSize)/1024/((audioEndTime-audioStartTime)/10000000); 
	return bitRate; 
} 
 
//设置是否是单音频 
void ZZLFileWriter::SetIsSingleAudio(BOOL abAudio) 
{ 
	mbIsSingleAudio = abAudio; 
} 
 
bool ZZLFileWriter::SaveBitRate() { 
	if(configHandle == INVALID_HANDLE_VALUE) 
		return false; 
 
	DWORD writenBytes = 0; 
	char temp[64]; 
	if(INVALID_SET_FILE_POINTER == SetFilePointer(configHandle, 0, 0, FILE_BEGIN)) 
		return false; 
	sprintf(temp, "BitRate=%.4f", GetBitRate()); 
	 
	// 注意:配置文件中所留的空间是“BitRate=000000000”,所以要防止超过这个长度 
	temp[strlen("BitRate=000000000")-1] = 0; 
 
	// 检查一下,某些情况下,最后码率是0,很奇怪 
	if(blockCount > 20) { 
		assert(strcmp(temp, "BitRate=000000000") != 0); 
	} 
 
	if(!WriteFile(configHandle, temp, strlen(temp), &writenBytes, NULL)) 
		return false; 
	if(writenBytes != strlen(temp)) 
		return false; 
	return true; 
} 
 
bool ZZLFileWriter::RemoveOldTmpFile(string path) { 
	WIN32_FIND_DATA fileData; 
	string match = path; 
	match.append("\\*"); 
	HANDLE hFind = FindFirstFile(match.data(), &fileData); 
	if(hFind == INVALID_HANDLE_VALUE) 
		return true; 
	bool firstDeleteFile = true; 
	while(1) { 
		bool shouldDelete = false; 
		if(stricmp(fileData.cFileName, "config") == 0)						// 配置文件 
			shouldDelete = true; 
		else if(stricmp(fileData.cFileName, "keysample") == 0)				// 关键帧文件 
			shouldDelete = true; 
		else if(stricmp(fileData.cFileName, (chnlName+".zzl").data()) == 0) // zzl文件 
			shouldDelete = true; 
		else { 
			// 如果是纯数字,说明是数据文件 
			 int itemp  = atoi(fileData.cFileName); 
			 char stemp[64]; 
			 itoa(itemp, stemp, 10); 
			 if(itemp >= 0 && stricmp(fileData.cFileName, stemp) == 0) 
				 shouldDelete = true; 
		} 
 
		if(shouldDelete) { 
			if(firstDeleteFile) { 
				firstDeleteFile = false; 
				TCHAR temp[1024]; 
				//sprintf(temp, "名字是 %s 的节目已经存在于目录 %s ,请问要删除旧的节目数据吗?(可能是被遗忘的有用数据)", chnlName.data(), path.data()); 
				//int answer = MessageBox(NULL, temp, "警告", MB_YESNO|MB_ICONQUESTION); 
				int answer = IDYES; 
				if(answer != IDNO) { 
					//MessageBox(NULL, "你选择删除旧的节目数据,新的节目开始压缩!", "通知", MB_OK|MB_ICONINFORMATION); 
					TraceLog1("现在覆盖旧的节目数据,新的节目开始压缩!\n"); 
				} 
				else { 
					sprintf(temp, "你选择保存旧的节目数据,此次压缩将被取消,请在转移目录 %s 下的数据之后,重新开始压缩。", path.data()); 
					MessageBox(NULL, temp, "通知", MB_OK|MB_ICONINFORMATION); 
					return false; 
				} 
			} 
			string temp = path+"\\"; 
			temp.append(fileData.cFileName); 
			DeleteFile(temp.data()); 
		} 
 
		if(!FindNextFile(hFind, &fileData)) { 
			if(GetLastError() == ERROR_NO_MORE_FILES) 
				break; 
			else { 
				assert(0); 
				return true;  
			} 
		} 
	} 
	FindClose(hFind); 
	return true; 
}