1761 lines
50 KiB
C++
1761 lines
50 KiB
C++
#include "rm_avirepair.h"
|
|
#include "rm_constants.h"
|
|
#include <QFile>
|
|
#include <QFileInfo>
|
|
#include <QDir>
|
|
#include <QDebug>
|
|
|
|
#ifdef Q_OS_WIN
|
|
#include <windows.h>
|
|
#endif
|
|
|
|
//#include "rm_fileio.h"
|
|
|
|
// Sub title 확인해서 처리해야 할 경우
|
|
#if (REPAIR_CHECK_SUBTITLE)
|
|
#include "rm_videogroup.h"
|
|
#include "rm_sensordata.h"
|
|
#if (RM_USE_SEPARATED_CH_FILE)
|
|
#include "rm_videoitem_2ch.h"
|
|
#else
|
|
#include "rm_videoitem.h"
|
|
#endif
|
|
#endif
|
|
|
|
class RMFileIO
|
|
{
|
|
private:
|
|
|
|
#ifdef Q_OS_WIN
|
|
HANDLE _f;
|
|
#else
|
|
FILE* _f;
|
|
#endif
|
|
QString _filePath;
|
|
|
|
public:
|
|
RMFileIO(QString& filePath, bool readOnly = false);
|
|
~RMFileIO();
|
|
bool isValid()
|
|
{
|
|
return (_f != NULL);
|
|
}
|
|
QString filePath()
|
|
{
|
|
return _filePath;
|
|
}
|
|
|
|
size_t GetLength();
|
|
size_t Read(void* buffer, size_t length);
|
|
void Close();
|
|
void Seek(long _Offset, int _Origin);
|
|
|
|
void Write(void* buffer, size_t length);
|
|
void SetLength(size_t length);
|
|
size_t GetPosition();
|
|
|
|
|
|
static bool Rename(QString& oldName, QString& newName);
|
|
static QString ReplaceFileNameOnly(const QString& src, const QString& search, const QString& replace);
|
|
};
|
|
|
|
|
|
// 파일명만 변경함
|
|
QString RMFileIO::ReplaceFileNameOnly(const QString& src, const QString& search, const QString& replace)
|
|
{
|
|
QFileInfo info = QFileInfo(src);
|
|
return QDir::cleanPath(info.dir().absolutePath() + QDir::separator() + info.baseName().replace(search,replace,Qt::CaseInsensitive) + "." + info.suffix());
|
|
}
|
|
|
|
bool RMFileIO::Rename(QString& oldName, QString& newName)
|
|
{
|
|
#ifdef Q_OS_WIN
|
|
// return ::MoveFileExW((LPCTSTR)oldName.utf16(),(LPCTSTR)newName.utf16(),MOVEFILE_REPLACE_EXISTING | MOVEFILE_WRITE_THROUGH);
|
|
QString oldWin = oldName.replace("/","\\");
|
|
QString newWin = newName.replace("/","\\");
|
|
if (::MoveFile((LPCTSTR)oldWin.utf16(), (LPCTSTR)newWin.utf16()) == FALSE)
|
|
{
|
|
qInfo() << "GetLastError():" << ::GetLastError();
|
|
qInfo() << "filePath:" << oldWin;
|
|
qInfo() << "destPath:" << newWin;
|
|
}
|
|
return TRUE;
|
|
#else
|
|
return QFile::rename(oldName,newName);
|
|
#endif
|
|
}
|
|
RMFileIO::RMFileIO(QString& filePath, bool readOnly)
|
|
{
|
|
_f = NULL;
|
|
_filePath = filePath;
|
|
#ifdef Q_OS_WIN
|
|
if(readOnly == true)
|
|
{
|
|
_f = ::CreateFile((LPCTSTR)_filePath.utf16(),
|
|
GENERIC_READ,
|
|
FILE_SHARE_READ,
|
|
NULL,
|
|
OPEN_EXISTING,
|
|
FILE_ATTRIBUTE_NORMAL,
|
|
NULL);
|
|
}
|
|
else
|
|
{
|
|
|
|
_f = ::CreateFile((LPCTSTR)_filePath.utf16(),
|
|
GENERIC_READ | GENERIC_WRITE,
|
|
FILE_SHARE_WRITE,
|
|
NULL,
|
|
OPEN_ALWAYS,
|
|
FILE_ATTRIBUTE_NORMAL,
|
|
NULL);
|
|
}
|
|
#else
|
|
_f = fopen(_filePath.toLocal8Bit(),"r+b");
|
|
#endif
|
|
}
|
|
RMFileIO::~RMFileIO()
|
|
{
|
|
Close();
|
|
}
|
|
size_t RMFileIO::GetLength()
|
|
{
|
|
#ifdef Q_OS_WIN
|
|
return (size_t)::GetFileSize(_f,NULL);
|
|
#else
|
|
long cur = ftell(_f);
|
|
fseek(_f, 0L, SEEK_END);
|
|
size_t fileSize = ftell(_f);
|
|
fseek(_f, cur, SEEK_SET);
|
|
return fileSize;
|
|
#endif
|
|
}
|
|
size_t RMFileIO::Read(void* buffer, size_t length)
|
|
{
|
|
#ifdef Q_OS_WIN
|
|
DWORD dwRead = 0;
|
|
if(::ReadFile(_f,buffer,length,&dwRead,NULL) == FALSE)
|
|
{
|
|
return 0;
|
|
}
|
|
return (size_t)dwRead;
|
|
#else
|
|
return fread(buffer,1,length,_f);
|
|
#endif
|
|
}
|
|
void RMFileIO::Write(void* buffer, size_t length)
|
|
{
|
|
#ifdef Q_OS_WIN
|
|
DWORD dwWrite = 0;
|
|
::WriteFile(_f,buffer,length,&dwWrite,NULL);
|
|
#else
|
|
fwrite(buffer,1,length,_f);
|
|
#endif
|
|
}
|
|
void RMFileIO::SetLength(size_t length)
|
|
{
|
|
#if (NO_FILE_RESIZE)
|
|
Q_UNUSED(length)
|
|
#else
|
|
#ifdef Q_OS_WIN
|
|
::SetFilePointer(_f,length,NULL,FILE_BEGIN);
|
|
::SetEndOfFile(_f);
|
|
#else
|
|
_chsize(fileno(_f),(long)length);
|
|
#endif
|
|
#endif // #if (!NO_FILE_RESIZE)
|
|
}
|
|
size_t RMFileIO::GetPosition()
|
|
{
|
|
#ifdef Q_OS_WIN
|
|
size_t position = (size_t)::SetFilePointer(_f,0,NULL,FILE_CURRENT);
|
|
return position;
|
|
#else
|
|
return ftell(_f);
|
|
#endif
|
|
}
|
|
|
|
void RMFileIO::Close()
|
|
{
|
|
#ifdef Q_OS_WIN
|
|
if(_f != NULL)
|
|
{
|
|
::CloseHandle(_f);
|
|
_f = NULL;
|
|
}
|
|
#else
|
|
if(_f != NULL)
|
|
{
|
|
fclose(_f);
|
|
_f = NULL;
|
|
}
|
|
#endif
|
|
}
|
|
void RMFileIO::Seek(long _Offset, int _Origin)
|
|
{
|
|
#ifdef Q_OS_WIN
|
|
|
|
DWORD method = FILE_BEGIN; // SEEK_SET
|
|
if(_Origin == SEEK_CUR)
|
|
{
|
|
method = FILE_CURRENT;
|
|
}
|
|
else if (_Origin == SEEK_END)
|
|
{
|
|
method = FILE_END;
|
|
}
|
|
::SetFilePointer(_f,_Offset,NULL,method);
|
|
#else
|
|
fseek(_f,_Offset,_Origin);
|
|
#endif
|
|
}
|
|
|
|
|
|
|
|
#ifndef FCC
|
|
#if (_MSC_VER)
|
|
#define FCC(ch4) ((((DWORD)(ch4) & 0xFF) << 24) | \
|
|
(((DWORD)(ch4) & 0xFF00) << 8) | \
|
|
(((DWORD)(ch4) & 0xFF0000) >> 8) | \
|
|
(((DWORD)(ch4) & 0xFF000000) >> 24))
|
|
#else // _MSC_VER
|
|
#define FCC(ch4) ((((uint32_t)(size_t)(ch4) & 0xFF) << 24) | \
|
|
(((uint32_t)(size_t)(ch4) & 0xFF00) << 8) | \
|
|
(((uint32_t)(size_t)(ch4) & 0xFF0000) >> 8) | \
|
|
(((uint32_t)(size_t)(ch4) & 0xFF000000) >> 24))
|
|
#endif // _MSC_VER
|
|
#endif
|
|
|
|
//#if (RM_MODEL == RM_MODEL_TYPE_TELEBIT)
|
|
//#define MANDO_TB2000 1
|
|
//#endif
|
|
|
|
//#ifdef MANDO_TB2000
|
|
|
|
//#define _ENCRYPT_SIZE 0xdc
|
|
//static BYTE *stc_pu8Data = NULL;
|
|
|
|
////static void efs_file_decrypt(FILE *fp)
|
|
//static void efs_file_decrypt(RMFileIO& file)
|
|
//{
|
|
// int i = 0;
|
|
// BYTE *temp = NULL;
|
|
// int length = _ENCRYPT_SIZE;
|
|
// int j = length - 1;
|
|
|
|
// if(stc_pu8Data == NULL)
|
|
// {
|
|
// stc_pu8Data = new BYTE [_ENCRYPT_SIZE];
|
|
// }
|
|
// temp = new BYTE [_ENCRYPT_SIZE];
|
|
|
|
// file.Read(stc_pu8Data,_ENCRYPT_SIZE);
|
|
//// fread(stc_pu8Data, _ENCRYPT_SIZE, 1, fp);
|
|
|
|
//#if 0
|
|
// temp[0] = (((stc_pu8Data[(size - 1)] & 0x0F) << 4) | ((stc_pu8Data[0] & 0xF0) >> 4));
|
|
// for(i = 1; i < size; i++)
|
|
// {
|
|
// temp[i] = (((stc_pu8Data[i-1] & 0x0F) << 4) | ((stc_pu8Data[i] & 0xF0) >> 4));
|
|
// }
|
|
//#else
|
|
// temp[0] = (((stc_pu8Data[(length - 1)] & 0x1F) << 3) | ((stc_pu8Data[0] & 0xE0) >> 5));
|
|
// for(i = 1; i < length; i++)
|
|
// {
|
|
// temp[i] = (((stc_pu8Data[i-1] & 0x1F) << 3) | ((stc_pu8Data[i] & 0xE0) >> 5));
|
|
// }
|
|
//#endif
|
|
|
|
// if(((temp[j] ^ 0xFF) == 'R') && ((temp[j-1] ^ 0xFF) == 'I') && ((temp[j-2] ^ 0xFF) == 'F') && ((temp[j-3] ^ 0xFF) == 'F'))
|
|
// {
|
|
// for(i = 0; i < length; i++)
|
|
// {
|
|
// stc_pu8Data[i] = temp[j--] ^ 0xFF;
|
|
// }
|
|
// }
|
|
|
|
// file.Seek(0,SEEK_SET);
|
|
//// fseek(fp, 0, SEEK_SET);
|
|
// delete [] temp;
|
|
//}
|
|
|
|
//void efs_file_encrypt(BYTE *pu8Data, int length)
|
|
//{
|
|
// int i = 0;
|
|
// BYTE *temp = NULL;
|
|
// int j = length - 1;
|
|
|
|
// temp = new BYTE [length];
|
|
|
|
// if(pu8Data[0] == 'R' && pu8Data[1] == 'I' && pu8Data[2] == 'F' && pu8Data[3] == 'F')
|
|
// {
|
|
// for(i = 0; i < length; i++)
|
|
// {
|
|
// temp[j--] = pu8Data[i] ^ 0xFF;
|
|
// }
|
|
//#if 0
|
|
// for(i = 0; i < (length - 1); i++)
|
|
// {
|
|
// pu8Data[i] = (((temp[i] & 0x0F) << 4) | ((temp[i+1] & 0xF0) >> 4));
|
|
// }
|
|
// pu8Data[(length - 1)] = (((temp[(length - 1)] & 0x0F) << 4) | ((temp[0] & 0xF0) >> 4));
|
|
//#else
|
|
// for(i = 0; i < (length - 1); i++)
|
|
// {
|
|
// pu8Data[i] = (((temp[i] & 0x07) << 5) | ((temp[i+1] & 0xF8) >> 3));
|
|
// }
|
|
// pu8Data[(length - 1)] = (((temp[(length - 1)] & 0x07) << 5) | ((temp[0] & 0xF8) >> 3));
|
|
//#endif
|
|
// }
|
|
|
|
// delete [] temp;
|
|
//}
|
|
//#endif // MANDO_TB2000
|
|
|
|
#include <cstdint>
|
|
static uint32_t GET_FCC (FILE *fp) {
|
|
unsigned char tmp[4] = {0,};
|
|
|
|
//#ifdef MANDO_TB2000
|
|
// int offset = (int)ftell(fp);
|
|
// if(offset < _ENCRYPT_SIZE)
|
|
// {
|
|
// tmp[0] = stc_pu8Data[offset++];
|
|
// tmp[1] = stc_pu8Data[offset++];
|
|
// tmp[2] = stc_pu8Data[offset++];
|
|
// tmp[3] = stc_pu8Data[offset++];
|
|
|
|
// fseek(fp, offset, SEEK_SET);
|
|
|
|
// return FCC (tmp);
|
|
// }
|
|
//#endif // MANDO_TB2000
|
|
|
|
tmp[0] = getc(fp);
|
|
tmp[1] = getc(fp);
|
|
tmp[2] = getc(fp);
|
|
tmp[3] = getc(fp);
|
|
|
|
return FCC (tmp);
|
|
}
|
|
|
|
static unsigned int GET_TCC (FILE *fp) {
|
|
char tmp[5] = {0,};
|
|
|
|
//#ifdef MANDO_TB2000
|
|
// int offset = (int)ftell(fp);
|
|
// if(offset < _ENCRYPT_SIZE)
|
|
// {
|
|
// tmp[0] = stc_pu8Data[offset++];
|
|
// tmp[1] = stc_pu8Data[offset++];
|
|
// tmp[2] = 0;
|
|
// tmp[3] = 0;
|
|
|
|
// fseek(fp, offset, SEEK_SET);
|
|
|
|
// return FCC (tmp);
|
|
// }
|
|
//#endif
|
|
|
|
tmp[0] = getc(fp);
|
|
tmp[1] = getc(fp);
|
|
tmp[2] = 0;
|
|
tmp[3] = 0;
|
|
|
|
return FCC (tmp);
|
|
}
|
|
|
|
|
|
#define RECOVERY_MAX_COUNT 8000
|
|
#define FILE_SIZE_INDEX 0x0004
|
|
#define MICORSECPERFRMAE_INDEX 0x0020 // 2018-09-12 추가
|
|
#define MAX_TRANSFER_RATE_INDEX 0x0024
|
|
#define TOTAL_FRAME_INDEX 0x0030
|
|
|
|
#define AVIH_FLAG_INDEX 0x002C // 2018-09-12 추가
|
|
#define STREAM_COUNT_INDEX 0x0038
|
|
#define BUFFER_SIZE_INDEX 0x003C
|
|
#define VIDEO_WIDTH_INDEX 0x0040
|
|
#define VIDEO_HEIGHT_INDEX 0x0044
|
|
|
|
#if 0
|
|
typedef DWORD FOURCC
|
|
typedef struct {
|
|
FOURCC fccType; //4
|
|
FOURCC fccHandler; //8
|
|
DWORD dwFlags; //12
|
|
WORD wPriority; //14
|
|
WORD wLanguage; //16
|
|
DWORD dwInitialFrames; //20
|
|
DWORD dwScale; //24
|
|
DWORD dwRate; /*28*//* dwRate / dwScale == samples/second */
|
|
DWORD dwStart; //32
|
|
DWORD dwLength; /* In units above... */
|
|
DWORD dwSuggestedBufferSize;
|
|
DWORD dwQuality;
|
|
DWORD dwSampleSize;
|
|
RECT rcFrame;
|
|
} AVIStreamHeader;
|
|
#endif
|
|
|
|
#define STREAM_LENGTH_INDEX 32 //0x008C
|
|
#define STREAM_SCALE_INDEX 20 //0x017C
|
|
#define STREAM_RATE_INDEX 24 //0x017C
|
|
#define STREAM_SAMPLERATE_INDEX 68
|
|
|
|
|
|
#define STREAM_AUDIO_CHANNEL_INDEX 66 // 2018/09/04 버전에서 추가됨 -> H265 AVI 만 적용
|
|
#define STREAM_TEXT_BUFFER_INDEX 36 // "
|
|
|
|
typedef struct _idx1_data_s {
|
|
unsigned int nCkID;
|
|
unsigned int nFlags;
|
|
unsigned int nOffset;
|
|
unsigned int nLength;
|
|
} _idx1_data_t;
|
|
|
|
#define STREAM_VIDEO_0 0x01
|
|
#define STREAM_VIDEO_1 0x02
|
|
#define STREAM_AUDIO_0 0x04
|
|
#define STREAM_TEXT_0 0x08
|
|
|
|
#define AVI_STREAM_MAX 4 // 2018/09/04 버전에서 추가됨 -> H265 AVI 만 적용
|
|
|
|
typedef struct _idx1_frame_s {
|
|
unsigned short nCkID;
|
|
unsigned short nFrame;
|
|
} _idx1_frame_t;
|
|
|
|
typedef struct _idx1_info_s {
|
|
unsigned char szIdx1[4];
|
|
unsigned int size;
|
|
|
|
_idx1_data_t idx_data[RECOVERY_MAX_COUNT];
|
|
_idx1_frame_t frame_list[RECOVERY_MAX_COUNT];
|
|
//unsigned char nCkID[RECOVERY_MAX_COUNT];
|
|
} _idx1_info_t;
|
|
|
|
/* Flags for AVI_INDEX_ENTRY */
|
|
#define AVIIF_LIST 0x00000001L
|
|
#define AVIIF_TWOCC 0x00000002L
|
|
/* keyframe doesn't need previous info to be decompressed */
|
|
#define AVIIF_KEYFRAME 0x00000010L
|
|
/* this chunk needs the frames following it to be used */
|
|
#define AVIIF_FIRSTPART 0x00000020L
|
|
/* this chunk needs the frames before it to be used */
|
|
#define AVIIF_LASTPART 0x00000040L
|
|
#define AVIIF_MIDPART (AVIIF_LASTPART|AVIIF_FIRSTPART)
|
|
/* this chunk doesn't affect timing ie palette change */
|
|
#define AVIIF_NOTIME 0x00000100L
|
|
#define AVIIF_COMPUSE 0x0FFF0000L
|
|
|
|
#define MKTAG(a,b,c,d) (a | (b << 8) | (c << 16) | (d << 24))
|
|
|
|
enum {
|
|
CHIP_A20 = 0, //AVI type2
|
|
CHIP_V35, //AVI type1
|
|
#if 0
|
|
MODEL_KV100 = 0,
|
|
MODEL_KH100,
|
|
MODEL_KP100,
|
|
#endif
|
|
MODEL_MAX
|
|
};
|
|
|
|
//inline DWORD RMGetFileSize(FILE* f)
|
|
//{
|
|
// long cur = ftell(f);
|
|
// fseek(f, 0L, SEEK_END);
|
|
// DWORD fileSize = (DWORD)ftell(f);
|
|
// fseek(f, cur, SEEK_SET);
|
|
// return fileSize;
|
|
//}
|
|
|
|
// file.Read(byTemp, 4);
|
|
inline size_t RMReadFile(FILE* f,unsigned char* buffer, uint32_t length)
|
|
{
|
|
return fread(buffer,length,1,f);
|
|
}
|
|
|
|
RMAVIRepair::RMAVIRepair(QObject *parent) : QObject(parent)
|
|
{
|
|
|
|
}
|
|
|
|
#if (REPAIR_FAILED_TAG)
|
|
void RMAVIRepair::rename_failed(QString& filePath)
|
|
{
|
|
QFileInfo* fileInfo = new QFileInfo(filePath);
|
|
#if (RM_IS_COMTEC)
|
|
QString fileName = fileInfo->fileName().replace("_SDEXIT","_f",Qt::CaseInsensitive);;
|
|
#else
|
|
QString fileName = fileInfo->fileName().replace("_EXIT","_f",Qt::CaseInsensitive);;
|
|
#endif
|
|
|
|
QString destPath = fileInfo->absoluteDir().path() + PATH_COMPONENT + fileName;
|
|
delete fileInfo;
|
|
RMFileIO::Rename(filePath,destPath);
|
|
}
|
|
#endif
|
|
|
|
#if (REPAIR_CHECK_SUBTITLE)
|
|
// 파일명과 비교하여
|
|
bool RMAVIRepair::compare_subtitle_time(QString& filePath, char* subtitle)
|
|
{
|
|
// 발생할 수 없음
|
|
QDateTime fileTime;
|
|
if(RMVideoItem::IsFeasible(filePath,&fileTime) == RMVideoGroup::TYPE_UNDEFINED)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
// ZDR026:2018-03-03 21:17:50 X: 0.00 Y: 0.00 Z: 0.00 000.0T 0.0V - --.------ - ---.------ - ---.-km/h E:255 M:255 EM:255 SA:0
|
|
// qInfo() << subtitle;
|
|
NMEA_INFO info = {0,};
|
|
if(RMSensorData::parse_subtitle_time(subtitle,&info))
|
|
{
|
|
QDateTime subtitleDate(QDate(info.nYear,info.nMonth,info.nDay),QTime(info.nHour,info.nMin,info.nSec));
|
|
//qInfo() << subtitleDate << ":" << fileTime;
|
|
//qInfo() << "SEC TO:" << subtitleDate.secsTo(fileTime) << " or " << fileTime.secsTo(subtitleDate);
|
|
return abs(subtitleDate.secsTo(fileTime)) < 1800; // 30분 미만
|
|
}
|
|
return true;
|
|
}
|
|
|
|
#endif
|
|
|
|
#if(H265_SUPPORT || RM_USE_H265_AVI_REPAIR || SUPPORT_AVI_FIX_DURL)
|
|
|
|
#if (SUPPORT_AVI_FIX_DURL) // 통합 뷰어의 경우 ZDR-TYPE05/06 동시 지원
|
|
bool RMAVIRepair::repairV50(QString& filePath, QString& destPath)
|
|
#else
|
|
bool RMAVIRepair::repair(QString& filePath, QString& destPath)
|
|
#endif
|
|
{
|
|
RMFileIO file = RMFileIO(filePath);
|
|
if(file.isValid() == false)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
#ifdef MANDO_TB2000
|
|
efs_file_decrypt(file);
|
|
if(stc_pu8Data == NULL)
|
|
{
|
|
return false;
|
|
}
|
|
#endif
|
|
|
|
unsigned char *pData = NULL;
|
|
unsigned int nVideo1Count = 0;
|
|
unsigned int nVideo2Count = 0;
|
|
unsigned int nAudioCount = 0;
|
|
unsigned int nFrameCount = 0;
|
|
unsigned int nFrameSize = 0;
|
|
unsigned int nFileSize = 0;
|
|
unsigned int nIdxOffset = 0;
|
|
unsigned long i = 0;
|
|
|
|
unsigned int nMoviSize = 0;
|
|
unsigned int nAudioLength = 0;
|
|
unsigned int nTextLength = 0;
|
|
unsigned int nMaxTransRate = 0;
|
|
unsigned int nAudioRate = 44101;//?????
|
|
unsigned int nAudioScale = 2;
|
|
unsigned int nAudioSampleRate = 44100;
|
|
unsigned int nAudioChannel = 1;
|
|
|
|
_idx1_info_t idx_info, *pIdx_info;
|
|
|
|
unsigned char byTemp[10];
|
|
unsigned int nTagName = 0;
|
|
unsigned int nListSize = 0;
|
|
unsigned int nListOffset = 0;
|
|
unsigned char bFindMovi = false;
|
|
|
|
unsigned int nStrhPos[AVI_STREAM_MAX] = { 0, 0, 0, 0 };
|
|
unsigned int nStreamCount = 0;
|
|
|
|
uint32_t dwFileSize = 0;
|
|
int nVideoId[2] = { -1, -1 };
|
|
int nSoundId = -1;
|
|
int nTxtId = -1;
|
|
|
|
unsigned int nAvihFlag = 0x00010010;
|
|
unsigned int nBufferSize = 192000;
|
|
unsigned int nFileWitdh = 2560;
|
|
unsigned int nFileHeight = 1440;
|
|
unsigned int nTextBufferSize = 0x20;
|
|
unsigned int nMicorSecPerFrmae = 0;
|
|
unsigned char bFindVidStream = 0;
|
|
|
|
pIdx_info = &idx_info;
|
|
memset(pIdx_info, 0x00, sizeof(_idx1_info_t));
|
|
memcpy(pIdx_info->szIdx1, "idx1", 4);
|
|
|
|
dwFileSize = (uint32_t)file.GetLength();
|
|
|
|
file.Read(byTemp, 4);
|
|
|
|
#ifdef MANDO_TB2000
|
|
if(memcmp(stc_pu8Data, "RIFF", 4))
|
|
{
|
|
return FALSE;
|
|
}
|
|
memcpy(&nFileSize, &stc_pu8Data[4], 4);
|
|
if(dwFileSize == (nFileSize + 8))
|
|
{
|
|
file.Close();
|
|
return true;
|
|
}
|
|
#else // MANDO_TB2000
|
|
if(memcmp(byTemp, "RIFF", 4))
|
|
{
|
|
file.Close();
|
|
#if (REPAIR_FAILED_TAG)
|
|
RMAVIRepair::rename_failed(filePath);
|
|
#endif
|
|
return false;
|
|
}
|
|
file.Read(&nFileSize, 4);
|
|
if(dwFileSize == (nFileSize + 8))
|
|
{
|
|
file.Close();
|
|
return true;
|
|
}
|
|
#endif // MANDO_TB2000
|
|
file.Seek(12, SEEK_SET);
|
|
|
|
nListOffset = 12;
|
|
#ifdef MANDO_TB2000
|
|
while(1)
|
|
{
|
|
if(nListOffset < _ENCRYPT_SIZE)
|
|
{
|
|
memcpy(byTemp, &stc_pu8Data[nListOffset], 8);
|
|
}
|
|
else
|
|
{
|
|
if(8 != file.Read(byTemp, 8))
|
|
break;
|
|
}
|
|
#else // MANDO_TB2000
|
|
while(8 == file.Read(byTemp, 8))
|
|
{
|
|
#endif // MANDO_TB2000
|
|
memcpy(&nTagName, &byTemp[0], 4);
|
|
memcpy(&nListSize, &byTemp[4], 4);
|
|
nListOffset += 8;
|
|
|
|
if(nTagName == MKTAG('L','I','S','T'))
|
|
{
|
|
#ifdef MANDO_TB2000
|
|
if(nListOffset < _ENCRYPT_SIZE)
|
|
memcpy(&nTagName, &stc_pu8Data[nListOffset], 4);
|
|
else
|
|
#endif
|
|
file.Read(&nTagName, 4);
|
|
nListOffset += 4;
|
|
|
|
if (nTagName == MKTAG('m','o','v','i'))
|
|
{
|
|
bFindMovi = true;
|
|
break;
|
|
}
|
|
else if (nTagName == MKTAG('h','d','r','l'))
|
|
{
|
|
}
|
|
else if (nTagName == MKTAG('s','t','r','l'))
|
|
{
|
|
}
|
|
else
|
|
{
|
|
#ifdef MANDO_TB2000
|
|
if(nListOffset < _ENCRYPT_SIZE)
|
|
memcpy(&nListSize, &stc_pu8Data[nListOffset], 4);
|
|
else
|
|
#endif
|
|
file.Read(&nListSize, 4);
|
|
nListOffset += nListSize;
|
|
}
|
|
}
|
|
else if(nTagName == MKTAG('s','t','r','h'))
|
|
{
|
|
if(nStreamCount < AVI_STREAM_MAX)
|
|
{
|
|
#ifdef MANDO_TB2000
|
|
if(nListOffset < _ENCRYPT_SIZE)
|
|
memcpy(&nTagName, &stc_pu8Data[nListOffset], 4);
|
|
else
|
|
#endif
|
|
file.Read(&nTagName, 4);
|
|
switch(nTagName)
|
|
{
|
|
case MKTAG('v','i','d','s') :
|
|
if(nVideoId[0] == -1)
|
|
{
|
|
unsigned int nVideoScale = 0;
|
|
unsigned int nVideoRate = 0;
|
|
|
|
file.Seek(16, SEEK_CUR);
|
|
#ifdef MANDO_TB2000
|
|
if(nListOffset < _ENCRYPT_SIZE)
|
|
memcpy(&nVideoScale, &stc_pu8Data[nListOffset+4+16], 4);
|
|
else
|
|
#endif
|
|
file.Read(&nVideoScale, 4);
|
|
#ifdef MANDO_TB2000
|
|
if(nListOffset < _ENCRYPT_SIZE)
|
|
memcpy(&nVideoRate, &stc_pu8Data[nListOffset+4+16+4], 4);
|
|
else
|
|
#endif
|
|
file.Read(&nVideoRate, 4);
|
|
nVideoId[0] = nStreamCount;
|
|
bFindVidStream = 1;
|
|
}
|
|
else
|
|
{
|
|
nVideoId[1] = nStreamCount;
|
|
}
|
|
nStrhPos[nStreamCount++] = nListOffset;
|
|
break;
|
|
case MKTAG('a','u','d','s') :
|
|
|
|
// 적용완료
|
|
nSoundId = nStreamCount;
|
|
nStrhPos[nStreamCount++] = nListOffset;
|
|
// STREAM_SCALE_INDEX = 20
|
|
#if (_MSC_VER)
|
|
file.Seek(STREAM_SCALE_INDEX-4,FILE_CURRENT); // TAG READ 4 BYTE 빼고 SEEK
|
|
#else
|
|
file.Seek(STREAM_SCALE_INDEX-4,SEEK_CUR); // TAG READ 4 BYTE 빼고 SEEK
|
|
#endif
|
|
file.Read(&nAudioScale,4);
|
|
// STREAM_RATE_INDEX = 66 (이미 20 SEEK + 4 BYTE READ 했으니 66-24 = 42
|
|
#if (_MSC_VER)
|
|
file.Seek(STREAM_AUDIO_CHANNEL_INDEX-STREAM_SCALE_INDEX-4,FILE_CURRENT);
|
|
#else
|
|
file.Seek(STREAM_AUDIO_CHANNEL_INDEX-STREAM_SCALE_INDEX-4,SEEK_CUR);
|
|
#endif
|
|
file.Read(&nAudioChannel,2);
|
|
// STREAM_SAMPLERATE_INDEX = 68 (= FILE CURSOR)
|
|
file.Read(&nAudioSampleRate,4);
|
|
nAudioRate = nAudioSampleRate * nAudioScale;
|
|
|
|
break;
|
|
|
|
case MKTAG('t','x','t','s') :
|
|
nTxtId = nStreamCount;
|
|
nStrhPos[nStreamCount++] = nListOffset;
|
|
break;
|
|
}
|
|
}
|
|
nListOffset += nListSize;
|
|
}
|
|
else if(nTagName == MKTAG('s','t','r','f'))
|
|
{
|
|
if(bFindVidStream)
|
|
{
|
|
#if (_MSC_VER)
|
|
file.Seek(4,FILE_CURRENT); // 4 BYTE 부터 시작
|
|
#else
|
|
file.Seek(4,SEEK_CUR); // 4 BYTE 부터 시작
|
|
#endif
|
|
file.Read(&nFileWitdh, 4);
|
|
file.Read(&nFileHeight, 4);
|
|
bFindVidStream = 0;
|
|
}
|
|
nListOffset += nListSize;
|
|
}
|
|
else
|
|
{
|
|
nListOffset += nListSize;
|
|
}
|
|
|
|
file.Seek(nListOffset, SEEK_SET);
|
|
}
|
|
|
|
if(bFindMovi == false)
|
|
{
|
|
file.Close();
|
|
#if (REPAIR_FAILED_TAG)
|
|
RMAVIRepair::rename_failed(filePath);
|
|
#endif
|
|
return false;
|
|
}
|
|
|
|
dwFileSize -= nListOffset;
|
|
pData = new unsigned char [dwFileSize];
|
|
file.Read(pData, dwFileSize);
|
|
//file.Close();
|
|
|
|
// 2018/11/15 fix 적용
|
|
nIdxOffset = nListOffset;
|
|
|
|
// 2019/06/13 복구시 시간 확인
|
|
#ifdef REPAIR_CHECK_SUBTITLE
|
|
bool reCoveryFirstTimeCheck = true;
|
|
#endif
|
|
|
|
i = 0;
|
|
while(i < dwFileSize)
|
|
{
|
|
if((pData[i] == '0') && (pData[i+1] == ('0'+nVideoId[0])) && (pData[i+2] == 'd') && (pData[i+3] == 'c'))
|
|
{
|
|
|
|
if((pData[i+8] == 0) && (pData[i+9] == 0) && (pData[i+10] == 0) && (pData[i+11] == 1))
|
|
{
|
|
memcpy(&pIdx_info->idx_data[nFrameCount].nCkID, &pData[i], 4);
|
|
if(pData[i+12] == 0x40)
|
|
{
|
|
pIdx_info->idx_data[nFrameCount].nFlags = AVIIF_KEYFRAME;
|
|
}
|
|
else
|
|
{
|
|
pIdx_info->idx_data[nFrameCount].nFlags = 0x00;
|
|
}
|
|
memcpy(&nFrameSize, &pData[i+4], 4);
|
|
pIdx_info->idx_data[nFrameCount].nLength = nFrameSize;
|
|
pIdx_info->idx_data[nFrameCount].nOffset = nIdxOffset;
|
|
|
|
pIdx_info->frame_list[nFrameCount].nCkID = STREAM_VIDEO_0;
|
|
pIdx_info->frame_list[nFrameCount].nFrame = nVideo1Count;
|
|
// 2018/11/09 FIX 적용
|
|
if(nFrameSize % 2)
|
|
{
|
|
nFrameSize++;
|
|
}
|
|
|
|
nIdxOffset += (nFrameSize + 8);
|
|
|
|
i += (nFrameSize + 8);
|
|
nFrameCount++;
|
|
nVideo1Count++;
|
|
}
|
|
else
|
|
{
|
|
break;
|
|
}
|
|
|
|
}
|
|
else if((pData[i] == '0') && (pData[i+1] == ('0'+nVideoId[1])) && (pData[i+2] == 'd') && (pData[i+3] == 'c'))
|
|
{
|
|
if((pData[i+8] == 0) && (pData[i+9] == 0) && (pData[i+10] == 0) && (pData[i+11] == 1))
|
|
{
|
|
memcpy(&pIdx_info->idx_data[nFrameCount].nCkID, &pData[i], 4);
|
|
if(pData[i+12] == 0x40)
|
|
{
|
|
pIdx_info->idx_data[nFrameCount].nFlags = AVIIF_KEYFRAME;
|
|
}
|
|
else
|
|
{
|
|
pIdx_info->idx_data[nFrameCount].nFlags = 0x00;
|
|
}
|
|
memcpy(&nFrameSize, &pData[i+4], 4);
|
|
pIdx_info->idx_data[nFrameCount].nLength = nFrameSize;
|
|
pIdx_info->idx_data[nFrameCount].nOffset = nIdxOffset;
|
|
|
|
pIdx_info->frame_list[nFrameCount].nCkID = STREAM_VIDEO_1;
|
|
pIdx_info->frame_list[nFrameCount].nFrame = nVideo2Count;
|
|
|
|
// 2018/11/09 FIX 적용
|
|
if(nFrameSize % 2)
|
|
{
|
|
nFrameSize++;
|
|
}
|
|
|
|
nIdxOffset += (nFrameSize + 8);
|
|
|
|
i += (nFrameSize + 8);
|
|
nFrameCount++;
|
|
nVideo2Count++;
|
|
}
|
|
else
|
|
{
|
|
break;
|
|
}
|
|
|
|
}
|
|
else if((pData[i] == '0') && (pData[i+1] == ('0'+nSoundId)) && (pData[i+2] == 'w') && (pData[i+3] == 'b'))
|
|
{
|
|
memcpy(&pIdx_info->idx_data[nFrameCount].nCkID, &pData[i], 4);
|
|
pIdx_info->idx_data[nFrameCount].nFlags = 0x00;
|
|
memcpy(&nFrameSize, &pData[i+4], 4);
|
|
if(nFrameSize % 2)
|
|
{
|
|
nFrameSize++;
|
|
}
|
|
pIdx_info->idx_data[nFrameCount].nLength = nFrameSize;
|
|
pIdx_info->idx_data[nFrameCount].nOffset = nIdxOffset;
|
|
|
|
pIdx_info->frame_list[nFrameCount].nCkID = STREAM_AUDIO_0;
|
|
pIdx_info->frame_list[nFrameCount].nFrame = nAudioCount;
|
|
// 2018/11/09 FIX 적용
|
|
if(nFrameSize % 2)
|
|
{
|
|
nFrameSize++;
|
|
}
|
|
nIdxOffset += (nFrameSize + 8);
|
|
nAudioLength += (nFrameSize >> nAudioChannel);
|
|
|
|
i += (nFrameSize + 8);
|
|
nFrameCount++;
|
|
nAudioCount++;
|
|
}
|
|
else if((pData[i] == '0') && (pData[i+1] == ('0'+nTxtId)) && (pData[i+2] == 't') && (pData[i+3] == 'x'))
|
|
{
|
|
memcpy(&pIdx_info->idx_data[nFrameCount].nCkID, &pData[i], 4);
|
|
pIdx_info->idx_data[nFrameCount].nFlags = 0x00;
|
|
memcpy(&nFrameSize, &pData[i+4], 4);
|
|
if(nFrameSize % 2)
|
|
{
|
|
nFrameSize++;
|
|
}
|
|
pIdx_info->idx_data[nFrameCount].nLength = nFrameSize;
|
|
pIdx_info->idx_data[nFrameCount].nOffset = nIdxOffset;
|
|
|
|
pIdx_info->frame_list[nFrameCount].nCkID = STREAM_TEXT_0;
|
|
pIdx_info->frame_list[nFrameCount].nFrame = nTextLength;
|
|
|
|
// 복구시 자막내 시간 정보와 파일명의 시간 정보가 30분 이상 차이가 발생하는 경우에는 파일 복구 하지 않도록
|
|
#ifdef REPAIR_CHECK_SUBTITLE
|
|
// 2019/06/13 샘플 데이터에서는 512 이상임 && (i+33 < 512)) -> 제거
|
|
if(reCoveryFirstTimeCheck)
|
|
{
|
|
reCoveryFirstTimeCheck=false;
|
|
// 30분 이상 차이날 경우
|
|
if(RMAVIRepair::compare_subtitle_time(filePath,(char*)&pData[i+8]) == false)
|
|
{
|
|
file.Close();
|
|
#if (REPAIR_FAILED_TAG)
|
|
RMAVIRepair::rename_failed(filePath);
|
|
#endif
|
|
return false;
|
|
}
|
|
}
|
|
#endif
|
|
// 2018/11/09 FIX 적용
|
|
if(nFrameSize % 2)
|
|
{
|
|
nFrameSize++;
|
|
}
|
|
nIdxOffset += (nFrameSize + 8);
|
|
|
|
i += (nFrameSize + 8);
|
|
nFrameCount++;
|
|
nTextLength++;
|
|
}
|
|
else
|
|
{
|
|
break;
|
|
}
|
|
|
|
if(nFrameCount > RECOVERY_MAX_COUNT)
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
#if 1 //Frame 정리
|
|
if(nFrameCount < 5)
|
|
{
|
|
file.Close();
|
|
#if (REPAIR_FAILED_TAG)
|
|
RMAVIRepair::rename_failed(filePath);
|
|
#endif
|
|
return false;
|
|
}
|
|
|
|
int nVideo1CountBk = nVideo1Count;
|
|
int nVideo2CountBk = nVideo2Count;
|
|
|
|
if(nVideo1CountBk) nVideo1CountBk--;
|
|
if(nVideo2CountBk) nVideo2CountBk--;
|
|
|
|
for(i = (nFrameCount - 1); i > 0 ; i--)
|
|
{
|
|
if(pIdx_info->frame_list[i].nCkID == STREAM_VIDEO_0)
|
|
{
|
|
if(pIdx_info->frame_list[i].nFrame == (nVideo1CountBk - 1))
|
|
break;
|
|
|
|
if(nVideo1Count) nVideo1Count--;
|
|
}
|
|
else if(pIdx_info->frame_list[i].nCkID == STREAM_VIDEO_1)
|
|
{
|
|
if(pIdx_info->frame_list[i].nFrame == (nVideo2CountBk - 1))
|
|
break;
|
|
|
|
if(nVideo2Count) nVideo2Count--;
|
|
}
|
|
else if(pIdx_info->frame_list[i].nCkID == STREAM_AUDIO_0)
|
|
{
|
|
if(nAudioCount)
|
|
{
|
|
nAudioLength -= (pIdx_info->idx_data[i].nLength >> nAudioChannel);
|
|
nAudioCount--;
|
|
}
|
|
}
|
|
else if(pIdx_info->frame_list[i].nCkID == STREAM_TEXT_0)
|
|
{
|
|
if(nTextLength)
|
|
{
|
|
nTextLength--;
|
|
}
|
|
}
|
|
}
|
|
|
|
nFrameCount = nVideo1Count + nVideo2Count + nAudioCount + nTextLength;
|
|
#endif // #if 1 //Frame 정리
|
|
|
|
// SINGLE CH???
|
|
//if((nVideo1Count < 5) || (nVideo2Count < 5))
|
|
if((nVideo1Count < 5) && (nVideo2Count < 5))
|
|
{
|
|
file.Close();
|
|
#if (REPAIR_FAILED_TAG)
|
|
RMAVIRepair::rename_failed(filePath);
|
|
#endif
|
|
return false;
|
|
}
|
|
|
|
pIdx_info->size = nFrameCount * 16;
|
|
nMoviSize = pIdx_info->idx_data[nFrameCount-1].nLength + pIdx_info->idx_data[nFrameCount-1].nOffset + 8;
|
|
|
|
// 2018/11/09 FIX 적용 -> 2018/11/15 다시 FIX
|
|
nMoviSize -= (nListOffset - 4);
|
|
if(nMoviSize % 2)
|
|
nMoviSize++;
|
|
|
|
nIdxOffset = nListOffset + nMoviSize - 4;
|
|
nFileSize = pIdx_info->size + nIdxOffset;
|
|
nMicorSecPerFrmae = 33333;
|
|
nMaxTransRate = 21170;
|
|
|
|
// 2018/11/15 다시 FIX
|
|
nMicorSecPerFrmae = 52356;
|
|
|
|
file.Seek(0, SEEK_SET);
|
|
file.Read(pData, nListOffset);
|
|
|
|
#ifdef MANDO_TB2000
|
|
memcpy(pData, stc_pu8Data, _ENCRYPT_SIZE);
|
|
#endif
|
|
|
|
memcpy(&pData[FILE_SIZE_INDEX], &nFileSize, 4);
|
|
memcpy(&pData[MAX_TRANSFER_RATE_INDEX], &nMaxTransRate, 4);
|
|
|
|
memcpy(&pData[MICORSECPERFRMAE_INDEX], &nMicorSecPerFrmae, 4);
|
|
memcpy(&pData[TOTAL_FRAME_INDEX], ((nVideo1Count > nVideo2Count) ? &nVideo1Count : &nVideo1Count), 4);
|
|
memcpy(&pData[AVIH_FLAG_INDEX], &nAvihFlag, 4);
|
|
memcpy(&pData[BUFFER_SIZE_INDEX], &nBufferSize, 4);
|
|
memcpy(&pData[STREAM_COUNT_INDEX], &nStreamCount, 4);
|
|
memcpy(&pData[VIDEO_WIDTH_INDEX], &nFileWitdh, 4);
|
|
memcpy(&pData[VIDEO_HEIGHT_INDEX], &nFileHeight, 4);
|
|
|
|
if(nVideoId[0] != (-1))
|
|
{
|
|
if(nStrhPos[nVideoId[0]])
|
|
{
|
|
memcpy(&pData[nStrhPos[nVideoId[0]]+STREAM_LENGTH_INDEX], &nVideo1Count, 4);
|
|
}
|
|
}
|
|
if(nVideoId[1] != (-1))
|
|
{
|
|
if(nStrhPos[nVideoId[1]])
|
|
{
|
|
memcpy(&pData[nStrhPos[nVideoId[1]]+STREAM_LENGTH_INDEX], &nVideo2Count, 4);
|
|
}
|
|
}
|
|
if(nSoundId != (-1))
|
|
{
|
|
if(nStrhPos[nSoundId])
|
|
{
|
|
// 이거 왜하는지 모르겠음
|
|
memcpy(&pData[nStrhPos[nSoundId]+STREAM_RATE_INDEX], &nAudioRate, 4);
|
|
memcpy(&pData[nStrhPos[nSoundId]+STREAM_LENGTH_INDEX], &nAudioLength, 4);
|
|
}
|
|
}
|
|
if(nTxtId != (-1))
|
|
{
|
|
if(nStrhPos[nTxtId])
|
|
{
|
|
memcpy(&pData[nStrhPos[nTxtId]+STREAM_LENGTH_INDEX], &nTextLength, 4);
|
|
memcpy(&pData[nStrhPos[nTxtId]+STREAM_TEXT_BUFFER_INDEX], &nTextBufferSize, 4);
|
|
}
|
|
}
|
|
memcpy(&pData[nListOffset-8], &nMoviSize, 4);
|
|
|
|
#ifdef MANDO_TB2000
|
|
memcpy(stc_pu8Data, pData, _ENCRYPT_SIZE);
|
|
efs_file_encrypt(pData, _ENCRYPT_SIZE);
|
|
#endif
|
|
|
|
file.Seek(0, SEEK_SET);
|
|
file.Write(pData, nListOffset);
|
|
delete [] pData;
|
|
|
|
file.Seek(nIdxOffset, SEEK_SET);
|
|
file.Write(pIdx_info, pIdx_info->size+8);
|
|
file.Close();
|
|
|
|
#if (!NO_FILE_RENAME)
|
|
QFileInfo* fileInfo = new QFileInfo(filePath);// fileInfo(filePath);
|
|
|
|
#if (RM_IS_COMTEC)
|
|
QString fileName = fileInfo->fileName().replace("_SDEXIT","_Restore",Qt::CaseInsensitive);;
|
|
#else
|
|
QString fileName = fileInfo->fileName().replace("_EXIT","_RCVR",Qt::CaseInsensitive);;
|
|
#endif
|
|
|
|
destPath = fileInfo->absoluteDir().path() + QDir::separator() + fileName;
|
|
delete fileInfo;
|
|
|
|
RMFileIO::Rename(filePath,destPath);
|
|
#endif
|
|
return true;
|
|
}
|
|
#endif // #if(H265_SUPPORT || RM_USE_H265_AVI_REPAIR || RM_USE_V50_AVI_REPAIR)
|
|
|
|
// H265 가 아닌 경우 또는 동시 지원일 경우
|
|
#if !(H265_SUPPORT || RM_USE_H265_AVI_REPAIR || RM_USE_V50_AVI_REPAIR) || (SUPPORT_AVI_FIX_DURL)
|
|
bool RMAVIRepair::repair(QString& filePath, QString& destPath)
|
|
{
|
|
RMFileIO file = RMFileIO(filePath);
|
|
if(file.isValid() == false)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
//CFile file;
|
|
unsigned char *pData = NULL;
|
|
unsigned int nVideoCount = 0;
|
|
unsigned int nVideo1Count = 0;
|
|
unsigned int nVideo2Count = 0;
|
|
unsigned int nAudioCount = 0;
|
|
unsigned int nFrameCount = 0;
|
|
unsigned int nFrameSize = 0;
|
|
unsigned int nFileSize = 0;
|
|
unsigned int nIdxOffset = 0;
|
|
unsigned long i = 0;
|
|
|
|
unsigned int nMoviSize = 0;
|
|
unsigned int nAudioLength = 0;
|
|
unsigned int nTextLength = 0;
|
|
unsigned int nMaxTransRate = 0;
|
|
unsigned int nAudioRate = 44101;//?????
|
|
unsigned int nAudioScale = 2;
|
|
unsigned int nAudioSampleRate = 44100;
|
|
unsigned int nAudioChannel = 1;
|
|
|
|
_idx1_info_t idx_info, *pIdx_info;
|
|
|
|
unsigned char byTemp[10];
|
|
unsigned int nTagName = 0;
|
|
unsigned int nListSize = 0;
|
|
unsigned int nListOffset = 0;
|
|
unsigned int nRatePerScale = 0;
|
|
unsigned char bFindMovi = false;
|
|
|
|
unsigned int nStrhPos[4] = { 0, 0, 0, 0 };
|
|
unsigned int nStreamCount = 0;
|
|
|
|
uint32_t dwFileSize = 0;
|
|
int nVideoId[2] = { -1, -1 };
|
|
int nSoundId = -1;
|
|
int nTxtId = -1;
|
|
int nModelNumber = CHIP_A20;
|
|
|
|
#ifdef MANDO_TB2000
|
|
efs_file_decrypt(file);
|
|
if(stc_pu8Data == NULL)
|
|
{
|
|
return FALSE;
|
|
}
|
|
#endif
|
|
|
|
pIdx_info = &idx_info;
|
|
memset(pIdx_info, 0x00, sizeof(_idx1_info_t));
|
|
memcpy(pIdx_info->szIdx1, "idx1", 4);
|
|
|
|
// if(file.Open(szFilename, CFile::modeReadWrite|CFile::typeBinary, NULL) == false)
|
|
// return false;
|
|
|
|
|
|
|
|
dwFileSize = (uint32_t)file.GetLength();
|
|
|
|
#ifdef MANDO_TB2000
|
|
if(memcmp(stc_pu8Data, "RIFF", 4))
|
|
{
|
|
return false;
|
|
}
|
|
memcpy(&nFileSize, &stc_pu8Data[4], 4);
|
|
if(dwFileSize == (nFileSize + 8))
|
|
{
|
|
file.Close();
|
|
return true;
|
|
}
|
|
#else
|
|
file.Read(byTemp, 4);
|
|
if(memcmp(byTemp, "RIFF", 4))
|
|
{
|
|
#if (REPAIR_FAILED_TAG)
|
|
RMAVIRepair::rename_failed(filePath);
|
|
#endif
|
|
file.Close();
|
|
return false;
|
|
}
|
|
file.Read(&nFileSize, 4);
|
|
if(dwFileSize == (nFileSize + 8))
|
|
{
|
|
file.Close();
|
|
return true;
|
|
}
|
|
#endif
|
|
file.Seek(12, SEEK_SET);
|
|
|
|
nListOffset = 12;
|
|
#ifdef MANDO_TB2000
|
|
while(1)
|
|
{
|
|
if(nListOffset < _ENCRYPT_SIZE)
|
|
{
|
|
memcpy(byTemp, &stc_pu8Data[nListOffset], 8);
|
|
}
|
|
else
|
|
{
|
|
if(8 != file.Read(byTemp, 8))
|
|
break;
|
|
}
|
|
#else
|
|
while(8 == file.Read(byTemp, 8))
|
|
{
|
|
#endif
|
|
memcpy(&nTagName, &byTemp[0], 4);
|
|
memcpy(&nListSize, &byTemp[4], 4);
|
|
nListOffset += 8;
|
|
|
|
if(nTagName == MKTAG('L','I','S','T'))
|
|
{
|
|
#ifdef MANDO_TB2000
|
|
if(nListOffset < _ENCRYPT_SIZE)
|
|
memcpy(&nTagName, &stc_pu8Data[nListOffset], 4);
|
|
else
|
|
#endif
|
|
file.Read(&nTagName, 4);
|
|
nListOffset += 4;
|
|
|
|
if (nTagName == MKTAG('m','o','v','i'))
|
|
{
|
|
bFindMovi = true;
|
|
break;
|
|
}
|
|
else if (nTagName == MKTAG('h','d','r','l'))
|
|
{
|
|
}
|
|
else if (nTagName == MKTAG('s','t','r','l'))
|
|
{
|
|
}
|
|
else
|
|
{
|
|
#ifdef MANDO_TB2000
|
|
if(nListOffset < _ENCRYPT_SIZE)
|
|
memcpy(&nListSize, &stc_pu8Data[nListOffset], 4);
|
|
else
|
|
#endif
|
|
file.Read(&nListSize, 4);
|
|
nListOffset += nListSize;
|
|
}
|
|
}
|
|
else if(nTagName == MKTAG('s','t','r','h'))
|
|
{
|
|
#ifdef MANDO_TB2000
|
|
if(nListOffset < _ENCRYPT_SIZE)
|
|
memcpy(&nTagName, &stc_pu8Data[nListOffset], 4);
|
|
else
|
|
#endif
|
|
file.Read(&nTagName, 4);
|
|
|
|
switch(nTagName)
|
|
{
|
|
case MKTAG('v','i','d','s') :
|
|
if(nVideoId[0] == -1)
|
|
{
|
|
unsigned int nVideoScale = 0;
|
|
unsigned int nVideoRate = 0;
|
|
|
|
file.Seek(16, SEEK_CUR);
|
|
#ifdef MANDO_TB2000
|
|
if(nListOffset < _ENCRYPT_SIZE)
|
|
memcpy(&nVideoScale, &stc_pu8Data[nListOffset+4+16], 4);
|
|
else
|
|
#endif
|
|
file.Read(&nVideoScale, 4);
|
|
|
|
#ifdef MANDO_TB2000
|
|
if(nListOffset < _ENCRYPT_SIZE)
|
|
memcpy(&nVideoRate, &stc_pu8Data[nListOffset+4+16+4], 4);
|
|
else
|
|
#endif
|
|
file.Read(&nVideoRate, 4);
|
|
|
|
if(nVideoScale) nRatePerScale = nVideoRate / nVideoScale;
|
|
nVideoId[0] = nStreamCount;
|
|
}
|
|
else
|
|
{
|
|
nVideoId[1] = nStreamCount;
|
|
}
|
|
nStrhPos[nStreamCount++] = nListOffset;
|
|
break;
|
|
case MKTAG('a','u','d','s') :
|
|
nSoundId = nStreamCount;
|
|
nStrhPos[nStreamCount++] = nListOffset;
|
|
|
|
if(nModelNumber == CHIP_V35)
|
|
{
|
|
file.Seek(62, SEEK_CUR);
|
|
file.Read(&nAudioChannel, 2);
|
|
}
|
|
break;
|
|
case MKTAG('t','x','t','s') :
|
|
nTxtId = nStreamCount;
|
|
nStrhPos[nStreamCount++] = nListOffset;
|
|
break;
|
|
}
|
|
|
|
nListOffset += nListSize;
|
|
}
|
|
else if(nTagName == MKTAG('s','t','r','d'))
|
|
{
|
|
nModelNumber = CHIP_V35;
|
|
nListOffset += nListSize;
|
|
}
|
|
else if(nTagName == MKTAG('a','v','i','h'))
|
|
{
|
|
unsigned int avihFlag;
|
|
|
|
file.Seek(12, SEEK_CUR);
|
|
file.Read(&avihFlag, 4);
|
|
|
|
if(avihFlag == 0x00010010)
|
|
{
|
|
nModelNumber = CHIP_V35;
|
|
}
|
|
else
|
|
{
|
|
nModelNumber = CHIP_A20;
|
|
}
|
|
nListOffset += nListSize;
|
|
}
|
|
else
|
|
{
|
|
nListOffset += nListSize;
|
|
}
|
|
|
|
file.Seek(nListOffset, SEEK_SET);
|
|
}
|
|
|
|
if(bFindMovi == false) return false;
|
|
|
|
dwFileSize -= nListOffset;
|
|
pData = new unsigned char [dwFileSize];
|
|
file.Read(pData, dwFileSize);
|
|
//file.Close();
|
|
|
|
#ifdef REPAIR_CHECK_SUBTITLE
|
|
bool reCoveryFirstTimeCheck = true;
|
|
#endif
|
|
|
|
if(nModelNumber == CHIP_A20) nIdxOffset = nListOffset;
|
|
else nIdxOffset = 4;
|
|
|
|
i = 0;
|
|
while(i < dwFileSize)
|
|
{
|
|
if((pData[i] == '0') && (pData[i+1] == ('0'+nVideoId[0])) && (pData[i+2] == 'd') && (pData[i+3] == 'c'))
|
|
{
|
|
if(nModelNumber == CHIP_A20)
|
|
{
|
|
if((pData[i+8] == 0) && (pData[i+9] == 0) && (pData[i+10] == 1))
|
|
{
|
|
memcpy(&pIdx_info->idx_data[nFrameCount].nCkID, &pData[i], 4);
|
|
if((pData[i+11] == 0x65)||(pData[i+11] == 0x67)) pIdx_info->idx_data[nFrameCount].nFlags = AVIIF_KEYFRAME;
|
|
else pIdx_info->idx_data[nFrameCount].nFlags = 0x00;
|
|
memcpy(&nFrameSize, &pData[i+4], 4);
|
|
pIdx_info->idx_data[nFrameCount].nLength = nFrameSize;
|
|
pIdx_info->idx_data[nFrameCount].nOffset = nIdxOffset;
|
|
|
|
pIdx_info->frame_list[nFrameCount].nCkID = STREAM_VIDEO_0;
|
|
pIdx_info->frame_list[nFrameCount].nFrame = nVideo1Count;
|
|
|
|
nIdxOffset += (nFrameSize + 8);
|
|
|
|
i += (nFrameSize + 8);
|
|
nFrameCount++;
|
|
nVideo1Count++;
|
|
}
|
|
else
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if((pData[i+8] == 0) && (pData[i+9] == 0) && (pData[i+10] == 0) && (pData[i+11] == 1))
|
|
{
|
|
memcpy(&pIdx_info->idx_data[nFrameCount].nCkID, &pData[i], 4);
|
|
if(pData[i+12] == 0x67) pIdx_info->idx_data[nFrameCount].nFlags = AVIIF_KEYFRAME;
|
|
else pIdx_info->idx_data[nFrameCount].nFlags = 0x00;
|
|
memcpy(&nFrameSize, &pData[i+4], 4);
|
|
pIdx_info->idx_data[nFrameCount].nLength = nFrameSize;
|
|
pIdx_info->idx_data[nFrameCount].nOffset = nIdxOffset;
|
|
|
|
pIdx_info->frame_list[nFrameCount].nCkID = STREAM_VIDEO_0;
|
|
pIdx_info->frame_list[nFrameCount].nFrame = nVideo1Count;
|
|
|
|
nIdxOffset += (nFrameSize + 8);
|
|
|
|
i += (nFrameSize + 8);
|
|
nFrameCount++;
|
|
nVideo1Count++;
|
|
}
|
|
else
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
else if((pData[i] == '0') && (pData[i+1] == ('0'+nVideoId[1])) && (pData[i+2] == 'd') && (pData[i+3] == 'c'))
|
|
{
|
|
if(nModelNumber == CHIP_A20)
|
|
{
|
|
if((pData[i+8] == 0) && (pData[i+9] == 0) && (pData[i+10] == 1))
|
|
{
|
|
memcpy(&pIdx_info->idx_data[nFrameCount].nCkID, &pData[i], 4);
|
|
if((pData[i+11] == 0x65)||(pData[i+11] == 0x67)) pIdx_info->idx_data[nFrameCount].nFlags = AVIIF_KEYFRAME;
|
|
else pIdx_info->idx_data[nFrameCount].nFlags = 0x00;
|
|
memcpy(&nFrameSize, &pData[i+4], 4);
|
|
pIdx_info->idx_data[nFrameCount].nLength = nFrameSize;
|
|
pIdx_info->idx_data[nFrameCount].nOffset = nIdxOffset;
|
|
|
|
pIdx_info->frame_list[nFrameCount].nCkID = STREAM_VIDEO_1;
|
|
pIdx_info->frame_list[nFrameCount].nFrame = nVideo2Count;
|
|
|
|
nIdxOffset += (nFrameSize + 8);
|
|
|
|
i += (nFrameSize + 8);
|
|
nFrameCount++;
|
|
nVideo2Count++;
|
|
}
|
|
else
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if((pData[i+8] == 0) && (pData[i+9] == 0) && (pData[i+10] == 0) && (pData[i+11] == 1))
|
|
{
|
|
memcpy(&pIdx_info->idx_data[nFrameCount].nCkID, &pData[i], 4);
|
|
if(pData[i+12] == 0x67) pIdx_info->idx_data[nFrameCount].nFlags = AVIIF_KEYFRAME;
|
|
else pIdx_info->idx_data[nFrameCount].nFlags = 0x00;
|
|
memcpy(&nFrameSize, &pData[i+4], 4);
|
|
pIdx_info->idx_data[nFrameCount].nLength = nFrameSize;
|
|
pIdx_info->idx_data[nFrameCount].nOffset = nIdxOffset;
|
|
|
|
pIdx_info->frame_list[nFrameCount].nCkID = STREAM_VIDEO_1;
|
|
pIdx_info->frame_list[nFrameCount].nFrame = nVideo2Count;
|
|
|
|
nIdxOffset += (nFrameSize + 8);
|
|
|
|
i += (nFrameSize + 8);
|
|
nFrameCount++;
|
|
nVideo2Count++;
|
|
}
|
|
else
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
else if((pData[i] == '0') && (pData[i+1] == ('0'+nSoundId)) && (pData[i+2] == 'w') && (pData[i+3] == 'b'))
|
|
{
|
|
memcpy(&pIdx_info->idx_data[nFrameCount].nCkID, &pData[i], 4);
|
|
pIdx_info->idx_data[nFrameCount].nFlags = 0x00;
|
|
memcpy(&nFrameSize, &pData[i+4], 4);
|
|
pIdx_info->idx_data[nFrameCount].nLength = nFrameSize;
|
|
pIdx_info->idx_data[nFrameCount].nOffset = nIdxOffset;
|
|
|
|
pIdx_info->frame_list[nFrameCount].nCkID = STREAM_AUDIO_0;
|
|
pIdx_info->frame_list[nFrameCount].nFrame = nAudioCount;
|
|
|
|
nIdxOffset += (nFrameSize + 8);
|
|
nAudioLength += (nFrameSize >> nAudioChannel);
|
|
|
|
i += (nFrameSize + 8);
|
|
nFrameCount++;
|
|
nAudioCount++;
|
|
}
|
|
else if((pData[i] == '0') && (pData[i+1] == ('0'+nTxtId)) && (pData[i+2] == 't') && (pData[i+3] == 'x'))
|
|
{
|
|
memcpy(&pIdx_info->idx_data[nFrameCount].nCkID, &pData[i], 4);
|
|
pIdx_info->idx_data[nFrameCount].nFlags = 0x00;
|
|
memcpy(&nFrameSize, &pData[i+4], 4);
|
|
pIdx_info->idx_data[nFrameCount].nLength = nFrameSize;
|
|
pIdx_info->idx_data[nFrameCount].nOffset = nIdxOffset;
|
|
|
|
pIdx_info->frame_list[nFrameCount].nCkID = STREAM_TEXT_0;
|
|
pIdx_info->frame_list[nFrameCount].nFrame = nTextLength;
|
|
|
|
// 복구시 자막내 시간 정보와 파일명의 시간 정보가 30분 이상 차이가 발생하는 경우에는 파일 복구 하지 않도록
|
|
#ifdef REPAIR_CHECK_SUBTITLE
|
|
// 2019/06/13 샘플 데이터에서는 512 이상임 && (i+33 < 512)) -> 제거
|
|
if(reCoveryFirstTimeCheck)
|
|
{
|
|
reCoveryFirstTimeCheck=false;
|
|
// 30분 이상 차이날 경우
|
|
if(RMAVIRepair::compare_subtitle_time(filePath,(char*)&pData[i+8]) == false)
|
|
{
|
|
file.Close();
|
|
#if (REPAIR_FAILED_TAG)
|
|
RMAVIRepair::rename_failed(filePath);
|
|
#endif
|
|
return false;
|
|
}
|
|
}
|
|
#endif
|
|
|
|
|
|
nIdxOffset += (nFrameSize + 8);
|
|
|
|
i += (nFrameSize + 8);
|
|
nFrameCount++;
|
|
nTextLength++;
|
|
}
|
|
else
|
|
{
|
|
break;
|
|
}
|
|
|
|
if(nFrameCount > RECOVERY_MAX_COUNT) break;
|
|
}
|
|
#if 0
|
|
if(nFrameCount < 5) return false;
|
|
|
|
int nVideo1CountBk = nVideo1Count;
|
|
int nVideo2CountBk = nVideo2Count;
|
|
|
|
if(nVideo1CountBk) nVideo1CountBk--;
|
|
if(nVideo2CountBk) nVideo2CountBk--;
|
|
|
|
for(i = (nFrameCount - 1); i > 0 ; i--)
|
|
{
|
|
if(pIdx_info->frame_list[i].nCkID == STREAM_VIDEO_0)
|
|
{
|
|
if(pIdx_info->frame_list[i].nFrame == (nVideo1CountBk - 1))
|
|
break;
|
|
|
|
if(nVideo1Count) nVideo1Count--;
|
|
}
|
|
else if(pIdx_info->frame_list[i].nCkID == STREAM_VIDEO_1)
|
|
{
|
|
if(pIdx_info->frame_list[i].nFrame == (nVideo2CountBk - 1))
|
|
break;
|
|
|
|
if(nVideo2Count) nVideo2Count--;
|
|
}
|
|
else if(pIdx_info->frame_list[i].nCkID == STREAM_AUDIO_0)
|
|
{
|
|
if(nAudioCount)
|
|
{
|
|
nAudioLength -= (pIdx_info->idx_data[i].nLength >> nAudioChannel);
|
|
nAudioCount--;
|
|
}
|
|
}
|
|
else if(pIdx_info->frame_list[i].nCkID == STREAM_TEXT_0)
|
|
{
|
|
if(nTextLength) nTextLength--;
|
|
}
|
|
}
|
|
|
|
nFrameCount = nVideo1Count + nVideo2Count + nAudioCount + nTextLength;
|
|
#endif
|
|
|
|
#if (USE_2CH_FOLDER)
|
|
if((nVideo1Count < 5) && (nVideo2Count < 5))
|
|
{
|
|
#if (REPAIR_FAILED_TAG)
|
|
RMAVIRepair::rename_failed(filePath);
|
|
#endif
|
|
file.Close();
|
|
return false;
|
|
}
|
|
#else
|
|
if((nVideo1Count < 5) || (nVideo2Count < 5)) return false;
|
|
#endif
|
|
|
|
pIdx_info->size = nFrameCount * 16;
|
|
nVideoCount = nVideo1Count + nVideo2Count;
|
|
|
|
file.Seek(0, SEEK_SET);
|
|
file.Read(pData, nListOffset);
|
|
|
|
#ifdef MANDO_TB2000
|
|
memcpy(pData, stc_pu8Data, _ENCRYPT_SIZE);
|
|
#endif
|
|
|
|
if(nModelNumber == CHIP_A20) nMoviSize = pIdx_info->idx_data[nFrameCount-1].nLength + pIdx_info->idx_data[nFrameCount-1].nOffset + 8 - (nListOffset - 4);
|
|
else nMoviSize = pIdx_info->idx_data[nFrameCount-1].nLength + pIdx_info->idx_data[nFrameCount-1].nOffset + 8;
|
|
nIdxOffset = nListOffset + nMoviSize - 4;
|
|
#if 1
|
|
nFileSize = nListOffset + pIdx_info->size + nMoviSize - 4;
|
|
#else
|
|
nFileSize = dwFileSize - 8;
|
|
#endif
|
|
|
|
if(nRatePerScale && nVideo1Count) nMaxTransRate = nMoviSize * nRatePerScale / nVideo1Count;
|
|
|
|
memcpy(&pData[FILE_SIZE_INDEX], &nFileSize, 4);
|
|
memcpy(&pData[MAX_TRANSFER_RATE_INDEX], &nMaxTransRate, 4);
|
|
if(nModelNumber == CHIP_A20) memcpy(&pData[TOTAL_FRAME_INDEX], ((nVideo1Count > nVideo2Count) ? &nVideo1Count : &nVideo1Count), 4);
|
|
else memcpy(&pData[TOTAL_FRAME_INDEX], &nVideoCount, 4);
|
|
if(nVideoId[0] != (-1))
|
|
{
|
|
if(nStrhPos[nVideoId[0]]) memcpy(&pData[nStrhPos[nVideoId[0]]+STREAM_LENGTH_INDEX], &nVideo1Count, 4);
|
|
}
|
|
if(nVideoId[1] != (-1))
|
|
{
|
|
if(nStrhPos[nVideoId[1]]) memcpy(&pData[nStrhPos[nVideoId[1]]+STREAM_LENGTH_INDEX], &nVideo2Count, 4);
|
|
}
|
|
if(nSoundId != (-1))
|
|
{
|
|
if(nStrhPos[nSoundId])
|
|
{
|
|
if(nModelNumber == CHIP_A20)
|
|
{
|
|
memcpy(&pData[nStrhPos[nSoundId]+STREAM_LENGTH_INDEX], &nAudioCount, 4);
|
|
}
|
|
else
|
|
{
|
|
memcpy(&nAudioScale, &pData[nStrhPos[nSoundId]+STREAM_SCALE_INDEX], 4);
|
|
memcpy(&nAudioSampleRate, &pData[nStrhPos[nSoundId]+STREAM_SAMPLERATE_INDEX], 4);
|
|
nAudioRate = nAudioSampleRate * nAudioScale;
|
|
nAudioRate += ((nAudioRate % 1000) / 100);
|
|
memcpy(&pData[nStrhPos[nSoundId]+STREAM_RATE_INDEX], &nAudioRate, 4);
|
|
memcpy(&pData[nStrhPos[nSoundId]+STREAM_LENGTH_INDEX], &nAudioLength, 4);
|
|
}
|
|
}
|
|
}
|
|
if(nTxtId != (-1))
|
|
{
|
|
if(nStrhPos[nTxtId]) memcpy(&pData[nStrhPos[nTxtId]+STREAM_LENGTH_INDEX], &nTextLength, 4);
|
|
}
|
|
memcpy(&pData[nListOffset-8], &nMoviSize, 4);
|
|
|
|
#ifdef MANDO_TB2000
|
|
memcpy(stc_pu8Data, pData, _ENCRYPT_SIZE);
|
|
efs_file_encrypt(pData, _ENCRYPT_SIZE);
|
|
#endif
|
|
|
|
file.Seek(0, SEEK_SET);
|
|
file.Write(pData, nListOffset);
|
|
delete [] pData;
|
|
|
|
file.Seek(nIdxOffset, SEEK_SET);
|
|
file.Write(pIdx_info, pIdx_info->size+8);
|
|
#if 1
|
|
#if (!NO_FILE_RESIZE)
|
|
file.SetLength(file.GetPosition());
|
|
#endif
|
|
#else
|
|
{
|
|
BYTE szTemp[4] = { 'J', 'U', 'N', 'K' };
|
|
int nJunkSize = dwFileSize - file.GetPosition() - 8;
|
|
|
|
file.Write(szTemp, 4);
|
|
file.Write(&nJunkSize, 4);
|
|
}
|
|
#endif
|
|
file.Close();
|
|
|
|
#if (!NO_FILE_RENAME)
|
|
destPath = filePath;
|
|
#if (RM_IS_COMTEC)
|
|
destPath = RMFileIO::ReplaceFileNameOnly(destPath,"_SDEXIT","_Restore");
|
|
//destPath = destPath.replace("_SDEXIT","_Restore",Qt::CaseInsensitive); // 대문자 사용하지 않음
|
|
#else
|
|
destPath = RMFileIO::ReplaceFileNameOnly(destPath,"_EXIT","_RCVR");
|
|
// destPath = destPath.replace("_EXIT","_RCVR",Qt::CaseInsensitive);
|
|
#endif
|
|
|
|
RMFileIO::Rename(filePath,destPath);
|
|
#endif
|
|
|
|
// TCHAR szOrgName[256];
|
|
|
|
// _tcscpy(szOrgName, szFilename);
|
|
// TCHAR *pExit = _tcsstr(szFilename, L"_EXIT");
|
|
|
|
// if(pExit)
|
|
// {
|
|
// #ifdef MANDO_TB2000
|
|
// _tcscpy(pExit, L"_RCVR.TBA");
|
|
// #else
|
|
// _tcscpy(pExit, L"_RCVR.AVI");
|
|
// #endif
|
|
// file.Rename(szOrgName, szFilename);
|
|
// }
|
|
|
|
return true;
|
|
}
|
|
#endif // H265 or NOT
|
|
|
|
bool RMAVIRepair::clipToPair(QString& filePath, QString& pairfilePath)
|
|
{
|
|
RMFileIO pairfile = RMFileIO(pairfilePath,true);
|
|
if(pairfile.isValid() == false)
|
|
{
|
|
return false;
|
|
}
|
|
size_t pairSize = pairfile.GetLength();
|
|
|
|
size_t copySize = qMin(51200,(int)pairSize); // 전체파일 쓰면 문제 발생함
|
|
|
|
unsigned char* buffer = (unsigned char*)malloc(copySize);
|
|
pairfile.Read(buffer,copySize); // 원본에서 읽음
|
|
pairfile.Close();
|
|
|
|
RMFileIO file = RMFileIO(filePath);
|
|
if(file.isValid() == false)
|
|
{
|
|
return false;
|
|
}
|
|
file.Write(buffer,copySize);
|
|
|
|
//file.Seek(pairSize,SEEK_SET);
|
|
#if (!NO_FILE_RESIZE)
|
|
file.SetLength(pairSize);
|
|
#endif
|
|
file.Close();
|
|
|
|
free(buffer);
|
|
|
|
//탐색기를 open한 상태에서 자동 갱신이 되지 않아서 한번더 writer 해줌.
|
|
/*
|
|
RMFileIO reReadFile = RMFileIO(filePath);
|
|
BYTE* byTemp = (BYTE*)malloc(51200);
|
|
reReadFile.Read(byTemp, 51200);
|
|
reReadFile.Close();
|
|
|
|
RMFileIO reWriteFile = RMFileIO(filePath);
|
|
reWriteFile.Write(byTemp,51200);
|
|
reWriteFile.Close();
|
|
*/
|
|
|
|
return true;
|
|
}
|