int FastReadStream::_Commit(int stream, __int64 i64BlockNo) { int iCacheBlock; int i; // Already have the block? for(i=0; i<lBlockCount; i++) if (pHeaders[i].i64BlockNo == i64BlockNo) { pHeaders[i].fAccessedBits |= 1L<<stream; // _RPT1(0,"Commit(%I64d): cache hit\n", i64BlockNo); return i; } // Pick a replacement candidate. iCacheBlock = _PickVictim(stream); // Replace it. try { ++lHistory; // _RPT2(0,"Commit(%I64d): cache miss (stream %d)\n", i64BlockNo, stream); if (iFile >= 0) { int iActual; if (-1 == _lseeki64(iFile, i64BlockNo * lBlockSize, SEEK_SET)) throw MyError("FastRead seek error: %s.", strerror(errno)); iActual = _read(iFile, (char *)pBuffer + iCacheBlock * lBlockSize, lBlockSize); if (iActual < 0) throw MyError("FastRead read error: %s.", strerror(errno)); pHeaders[iCacheBlock].lBytes = iActual; } else { LONG lLow = (LONG)i64BlockNo*lBlockSize; LONG lHigh = (LONG)((i64BlockNo*lBlockSize) >> 32); DWORD err, dwActual; if (0xFFFFFFFF == SetFilePointer(hFile, lLow, &lHigh, FILE_BEGIN)) if ((err = GetLastError()) != NO_ERROR) throw MyWin32Error("FastRead seek error: %%s", GetLastError()); if (!ReadFile(hFile, (char *)pBuffer + iCacheBlock * lBlockSize, lBlockSize, &dwActual, NULL)) throw MyWin32Error("FastRead read error: %%s", GetLastError()); pHeaders[iCacheBlock].lBytes = dwActual; } pHeaders[iCacheBlock].i64BlockNo = i64BlockNo; pHeaders[iCacheBlock].fAccessedBits = 1L<<stream; pHeaders[iCacheBlock].lHistoryVal = lHistory; } catch(...) { pHeaders[iCacheBlock].i64BlockNo = -1; pHeaders[iCacheBlock].fAccessedBits = 0; } return iCacheBlock; }
void tool_resbind(const std::vector<const char *>& args, const std::vector<const char *>& switches, bool amd64) { if (args.size() != 4) { printf("usage: resbind <exe-name> <source file> <restype> <resname>\n"); exit(5); } const char *exename = args[0]; const char *srcfile = args[1]; const char *restype = args[2]; const char *resname = args[3]; VDFile file(srcfile); vdblock<char> buf((size_t)file.size()); file.read(buf.data(), buf.size()); file.close(); HANDLE hUpdate = BeginUpdateResource(exename, FALSE); if (!hUpdate) throw MyWin32Error("Cannot open \"%s\" for resource edit: %%s.", GetLastError(), exename); BOOL success = UpdateResource(hUpdate, restype, resname, 0x0409, buf.data(), buf.size()); DWORD err = GetLastError(); EndUpdateResource(hUpdate, !success); if (!success) throw MyWin32Error("Cannot update \"%s\": %%s.", err, exename); printf("Adding \"%s\" to \"%s\" as %s:%s.\n", srcfile, exename, restype, resname); }
void VDFileAsyncNT::Open(VDFileHandle h, uint32 count, uint32 bufferSize) { try { mFilename = "<anonymous pipe>"; HANDLE hProcess = GetCurrentProcess(); if (!DuplicateHandle(hProcess, h, hProcess, &mhFileSlow, 0, FALSE, DUPLICATE_SAME_ACCESS)) throw MyWin32Error("Unable to open file \"%s\" for write: %%s", GetLastError(), mFilename.c_str()); mSectorSize = 4096; // guess for now... proper way would be GetVolumeMountPoint() followed by GetDiskFreeSpace(). mBlockSize = bufferSize; mBlockCount = count; mBufferSize = mBlockSize * mBlockCount; mWriteOffset = 0; mBufferLevel = 0; mState = kStateNormal; if (mhFileFast != INVALID_HANDLE_VALUE) { mpBlocks = new VDFileAsyncNTBuffer[count]; mBuffer.resize(count * bufferSize); ThreadStart(); } } catch(const MyError&) { Close(); throw; } }
void VDFileAsync9x::Open(const wchar_t *pszFilename, uint32 count, uint32 bufferSize) { try { mFilename = VDTextWToA(pszFilename); const DWORD slowFlags = mbWriteThrough ? FILE_ATTRIBUTE_NORMAL | FILE_FLAG_WRITE_THROUGH : FILE_ATTRIBUTE_NORMAL; mhFileSlow = CreateFileA(mFilename.c_str(), GENERIC_WRITE, FILE_SHARE_WRITE, NULL, CREATE_ALWAYS, slowFlags, NULL); if (mhFileSlow == INVALID_HANDLE_VALUE) throw MyWin32Error("Unable to open file \"%s\" for write: %%s", GetLastError(), mFilename.c_str()); if (mbUseFastMode) mhFileFast = CreateFileA(mFilename.c_str(), GENERIC_WRITE, FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_NO_BUFFERING, NULL); mSectorSize = 4096; // guess for now... proper way would be GetVolumeMountPoint() followed by GetDiskFreeSpace(). mBlockSize = bufferSize; mBlockCount = count; mBuffer.Init(count * bufferSize); mState = kStateNormal; } catch(const MyError&) { Close(); throw; } ThreadStart(); }
void VDFileSetAttributes(const wchar_t *path, uint32 attrsToChange, uint32 newAttrs) { const uint32 nativeAttrMask = VDFileGetNativeAttributesFromAttrsW32(attrsToChange); const uint32 nativeAttrVals = VDFileGetNativeAttributesFromAttrsW32(newAttrs); if (VDIsWindowsNT()) { DWORD nativeAttrs = ::GetFileAttributesW(path); if (nativeAttrs != INVALID_FILE_ATTRIBUTES) { nativeAttrs ^= (nativeAttrs ^ nativeAttrVals) & nativeAttrMask; if (::SetFileAttributesW(path, nativeAttrs)) return; } } else { VDStringA pathA(VDTextWToA(path)); DWORD nativeAttrs = ::GetFileAttributesA(pathA.c_str()); if (nativeAttrs != INVALID_FILE_ATTRIBUTES) { nativeAttrs ^= (nativeAttrs ^ nativeAttrVals) & nativeAttrMask; if (::SetFileAttributesA(pathA.c_str(), nativeAttrs)) return; } } throw MyWin32Error("Cannot change attributes on \"%ls\": %%s.", GetLastError(), path); }
void VDFileAsyncNT::Open(const wchar_t *pszFilename, uint32 count, uint32 bufferSize) { try { mFilename = VDTextWToA(pszFilename); mhFileSlow = CreateFileW(pszFilename, GENERIC_WRITE, FILE_SHARE_WRITE, NULL, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); if (mhFileSlow == INVALID_HANDLE_VALUE) throw MyWin32Error("Unable to open file \"%s\" for write: %%s", GetLastError(), mFilename.c_str()); mhFileFast = CreateFileW(pszFilename, GENERIC_WRITE, FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_NO_BUFFERING | FILE_FLAG_OVERLAPPED, NULL); if (mhFileFast == INVALID_HANDLE_VALUE) mhFileFast = CreateFileW(pszFilename, GENERIC_WRITE, FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_WRITE_THROUGH | FILE_FLAG_OVERLAPPED, NULL); mSectorSize = 4096; // guess for now... proper way would be GetVolumeMountPoint() followed by GetDiskFreeSpace(). mBlockSize = bufferSize; mBlockCount = count; mBufferSize = mBlockSize * mBlockCount; mWriteOffset = 0; mBufferLevel = 0; mState = kStateNormal; if (mhFileFast != INVALID_HANDLE_VALUE) { mpBlocks = new VDFileAsyncNTBuffer[count]; mBuffer.resize(count * bufferSize); ThreadStart(); } } catch(const MyError&) { Close(); throw; } }
void VDFileAsyncNT::Write(sint64 pos, const void *p, uint32 bytes) { Seek(pos); DWORD dwActual; if (!WriteFile(mhFileSlow, p, bytes, &dwActual, NULL) || (mClientSlowPointer += dwActual),(dwActual != bytes)) throw MyWin32Error("Write error occurred on file \"%s\": %%s", GetLastError(), mFilename.c_str()); }
VDStringW VDGetSystemPathNT() { wchar_t path[MAX_PATH]; if (!GetSystemDirectoryW(path, MAX_PATH)) throw MyWin32Error("Cannot locate system directory: %%s", GetLastError()); return VDStringW(path); }
VDStringW VDGetSystemPath9x() { char path[MAX_PATH]; if (!GetSystemDirectoryA(path, MAX_PATH)) throw MyWin32Error("Cannot locate system directory: %%s", GetLastError()); return VDTextAToW(path); }
sint64 VDFileAsyncNT::GetSize() { DWORD dwSizeHigh; DWORD dwSizeLow = GetFileSize(mhFileSlow, &dwSizeHigh); if (dwSizeLow == (DWORD)-1 && GetLastError() != NO_ERROR) throw MyWin32Error("I/O error on file \"%s\": %%s", GetLastError(), mFilename.c_str()); return dwSizeLow + ((sint64)dwSizeHigh << 32); }
void VDMoveFile(const wchar_t *srcPath, const wchar_t *dstPath) { bool success; if (VDIsWindowsNT()) { success = MoveFileW(srcPath, dstPath) != 0; } else { success = MoveFileA(VDTextWToA(srcPath).c_str(), VDTextWToA(dstPath).c_str()) != 0; } if (!success) throw MyWin32Error("Cannot rename \"%ls\" to \"%ls\": %%s", GetLastError(), srcPath, dstPath); }
void AVIOutputFile::_flushHdr() { DWORD dwActual; DWORD dwError; if (0xFFFFFFFF == SetFilePointer(hFile, 0, NULL, FILE_BEGIN)) if ((dwError = GetLastError()) != NO_ERROR) throw MyWin32Error("%s: %%s", dwError, szME); i64FilePosition = 0; if (!WriteFile(hFile, pHeaderBlock, nHeaderLen, &dwActual, NULL) || dwActual != nHeaderLen) throw MyWin32Error("%s: %%s", GetLastError(), szME); i64FilePosition = nHeaderLen; if (i64FilePosition > i64FarthestWritePoint) i64FarthestWritePoint = i64FilePosition; }
void VDShowHelp(HWND hwnd, const wchar_t *filename) { try { VDStringW helpFile(VDGetHelpPath()); if (!VDDoesPathExist(helpFile.c_str())) throw MyError("Cannot find help file: %ls", helpFile.c_str()); // If we're on Windows NT, check for the ADS and/or network drive. if (VDIsWindowsNT()) { VDStringW helpFileADS(helpFile); helpFileADS += L":Zone.Identifier"; if (VDDoesPathExist(helpFileADS.c_str())) { int rv = MessageBox(hwnd, "VirtualDub has detected that its help file, VirtualDub.chm, has an Internet Explorer download location marker on it. This may prevent the help file from being displayed properly, resulting in \"Action canceled\" errors being displayed. Would you like to remove it?", "VirtualDub warning", MB_YESNO|MB_ICONEXCLAMATION); if (rv == IDYES) DeleteFileW(helpFileADS.c_str()); } } if (filename) { helpFile.append(L"::/"); helpFile.append(filename); } VDStringW helpCommand(VDStringW(L"\"hh.exe\" \"") + helpFile + L'"'); PROCESS_INFORMATION pi; BOOL retval; // CreateProcess will actually modify the string that it gets, soo.... if (VDIsWindowsNT()) { STARTUPINFOW si = {sizeof(STARTUPINFOW)}; std::vector<wchar_t> tempbufW(helpCommand.size() + 1, 0); helpCommand.copy(&tempbufW[0], tempbufW.size()); retval = CreateProcessW(NULL, &tempbufW[0], NULL, NULL, FALSE, CREATE_DEFAULT_ERROR_MODE, NULL, NULL, &si, &pi); } else { STARTUPINFOA si = {sizeof(STARTUPINFOA)}; VDStringA strA(VDTextWToA(helpCommand)); std::vector<char> tempbufA(strA.size() + 1, 0); strA.copy(&tempbufA[0], tempbufA.size()); retval = CreateProcessA(NULL, &tempbufA[0], NULL, NULL, FALSE, CREATE_DEFAULT_ERROR_MODE, NULL, NULL, &si, &pi); } if (retval) { CloseHandle(pi.hThread); CloseHandle(pi.hProcess); } else throw MyWin32Error("Cannot launch HTML Help: %%s", GetLastError()); } catch(const MyError& e) { e.post(hwnd, g_szError); } }
VDStringW VDGetProgramFilePath() { union { wchar_t w[MAX_PATH]; char a[MAX_PATH]; } buf; VDStringW wstr; if (VDIsWindowsNT()) { if (!GetModuleFileNameW(NULL, buf.w, MAX_PATH)) throw MyWin32Error("Unable to get program path: %%s", GetLastError()); wstr = buf.w; } else { if (GetModuleFileNameA(NULL, buf.a, MAX_PATH)) throw MyWin32Error("Unable to get program path: %%s", GetLastError()); wstr = VDTextAToW(buf.a, -1); } return wstr; }
void tool_resextract(const std::vector<const char *>& args, const std::vector<const char *>& switches, bool amd64) { if (args.size() != 2) { printf("usage: resextract <exe-name> <output file>\n"); exit(5); } const char *exename = args[0]; const char *outfile = args[1]; VDTextOutputFile out(VDTextAToW(outfile).c_str()); HMODULE hmod = LoadLibraryEx(exename, NULL, LOAD_LIBRARY_AS_DATAFILE); if (!hmod) throw MyWin32Error("Cannot load executable module \"%s\": %%s", GetLastError(), exename); EnumResourceTypes(hmod, EnumResTypesCB, (LONG_PTR)&out); FreeLibrary(hmod); }
void VDRemoveDirectory(const wchar_t *path) { VDStringW::size_type l(wcslen(path)); if (l) { const wchar_t c = path[l-1]; if (c == L'/' || c == L'\\') { VDCreateDirectory(VDStringW(path, l-1).c_str()); return; } } BOOL succeeded; if (!(GetVersion() & 0x80000000)) { succeeded = RemoveDirectoryW(path); } else { succeeded = RemoveDirectoryA(VDTextWToA(path).c_str()); } if (!succeeded) throw MyWin32Error("Cannot remove directory: %%s", GetLastError()); }
BOOL AVIOutputFile::finalize() { AVISUPERINDEX asi_video; AVISUPERINDEX asi_audio; AVISUPERINDEX asi_audio2; struct _avisuperindex_entry asie_video[MAX_SUPERINDEX_ENTRIES]; struct _avisuperindex_entry asie_audio[MAX_SUPERINDEX_ENTRIES]; struct _avisuperindex_entry asie_audio2[MAX_SUPERINDEX_ENTRIES]; DWORD dw; int i; if (!fInitComplete) return TRUE; if (videoOut) if (!videoOut->finalize()) return FALSE; if (audioOut) if (!audioOut->finalize()) return FALSE; if (audio2Out) if (!audio2Out->finalize()) return FALSE; // fast path: clean it up and resync slow path. // create extended indices if (fExtendedAVI && xblock != 0) { _createNewIndices(index_video, &asi_video, asie_video, false); if (audioOut) _createNewIndices(index_audio, &asi_audio, asie_audio, audioOut); if (audio2Out) _createNewIndices(index_audio2, &asi_audio2, asie_audio2, audio2Out); } // finish last Xblock _closeXblock(); if (fastIO) { char pad[2048+8]; // pad to next boundary _RPT1(0,"AVIOutputFile: starting pad at position %08I64x\n", i64FilePosition); *(long *)(pad + 0) = 'KNUJ'; *(long *)(pad + 4) = (2048 - ((i64FilePosition+8)&2047))&2047; memset(pad+8, 0, 2048); _write(pad, *(long *)(pad+4) + 8); // flush fast path, get disk position fastIO->Flush1(); fastIO->Flush2(hFile); // seek slow path up _seekDirect(i64FilePosition); } // truncate file SetEndOfFile(hFile); _RPT0(0,"AVIOutputFile: Writing main AVI header...\n"); _seekHdr(main_hdr_pos+8); _writeHdr(&avihdr, sizeof avihdr); _RPT0(0,"AVIOutputFile: Writing video header...\n"); _seekHdr(video_hdr_pos+8); _writeHdr(&videoOut->streamInfo, sizeof(AVIStreamHeader_fixed)); if (audioOut) { _RPT0(0,"AVIOutputFile: Writing audio header...\n"); _seekHdr(audio_hdr_pos+8); _writeHdr(&audioOut->streamInfo, sizeof(AVIStreamHeader_fixed)); // we have to rewrite the audio format, in case someone // fixed fields in the format afterward (MPEG-1/L3) _RPT0(0,"AVIOutputFile: Writing audio format...\n"); _seekHdr(audio_format_pos+8); _writeHdr(audioOut->getFormat(), audioOut->getFormatLen()); } if (audio2Out) { _RPT0(0,"AVIOutputFile: Writing audio2 header...\n"); _seekHdr(audio2_hdr_pos+8); _writeHdr(&audio2Out->streamInfo, sizeof(AVIStreamHeader_fixed)); // we have to rewrite the audio format, in case someone // fixed fields in the format afterward (MPEG-1/L3) _RPT0(0,"AVIOutputFile: Writing audio2 format...\n"); _seekHdr(audio2_format_pos+8); _writeHdr(audio2Out->getFormat(), audio2Out->getFormatLen()); } if (fExtendedAVI) { _RPT0(0,"AVIOutputFile: writing dmlh header...\n"); _seekHdr(dmlh_pos+8); dw = videoOut->streamInfo.dwLength; _writeHdr(&dw, 4); if (xblock > 1) { _RPT0(0,"AVIOutputFile: writing video superindex...\n"); _seekHdr(video_indx_pos); _writeHdr(&asi_video, sizeof asi_video); _writeHdr(asie_video, sizeof(_avisuperindex_entry)*MAX_SUPERINDEX_ENTRIES); if (audioOut) { _seekHdr(audio_indx_pos); _writeHdr(&asi_audio, sizeof asi_audio); _writeHdr(asie_audio, sizeof(_avisuperindex_entry)*MAX_SUPERINDEX_ENTRIES); } if (audio2Out) { _seekHdr(audio2_indx_pos); _writeHdr(&asi_audio2, sizeof asi_audio2); _writeHdr(asie_audio2, sizeof(_avisuperindex_entry)*MAX_SUPERINDEX_ENTRIES); } } } if (pSegmentHint) { _seekHdr(seghint_pos+8); _writeHdr(pSegmentHint, cbSegmentHint); } _flushHdr(); _RPT0(0,"AVIOutputFile: closing RIFF and movi chunks...\n"); for(i=0; i<xblock; i++) { DWORD dwLen; dwLen = (DWORD)avi_riff_len[i]; _seekDirect(avi_riff_pos[i]+4); _writeDirect(&dwLen, 4); dwLen = (DWORD)avi_movi_len[i]; _seekDirect(avi_movi_pos[i]+4); _writeDirect(&dwLen, 4); } // if (!FlushFileBuffers(hFile)) // throw MyWin32Error("%s: %%s", GetLastError(), szME); // What do you do when a close fails? if (!CloseHandle(hFile)) { hFile = NULL; throw MyWin32Error("%s: %%s", GetLastError(), szME); } hFile = NULL; return TRUE; }
BOOL AVIOutputFile::_init(const char *szFile, LONG xSize, LONG ySize, BOOL videoIn, BOOL audioIn, BOOL audio2In, LONG bufferSize, BOOL is_interleaved, bool fThreaded) { AVISUPERINDEX asi={0}; struct _avisuperindex_entry asie_dumb[MAX_SUPERINDEX_ENTRIES]; fLimitTo4Gb = IsFilenameOnFATVolume(szFile); if (audio2In) { if (!audio2Out) return FALSE; } else { delete audio2Out; audio2Out = NULL; } if (audioIn) { if (!audioOut) return FALSE; } else { delete audioOut; audioOut = NULL; } if (!videoOut) return FALSE; // Allocate indexes if (!(index = new AVIIndex())) return FALSE; if (fExtendedAVI) { if (!(index_audio2 = new AVIIndex())) return FALSE; if (!(index_audio = new AVIIndex())) return FALSE; if (!(index_video = new AVIIndex())) return FALSE; } // Initialize main AVI header (avih) memset(&avihdr, 0, sizeof avihdr); avihdr.dwMicroSecPerFrame = MulDivUnsigned(videoOut->streamInfo.dwScale, 1000000U, videoOut->streamInfo.dwRate); avihdr.dwMaxBytesPerSec = 0; avihdr.dwPaddingGranularity = 0; avihdr.dwFlags = AVIF_HASINDEX | (is_interleaved ? AVIF_ISINTERLEAVED : 0); avihdr.dwTotalFrames = videoOut->streamInfo.dwLength; avihdr.dwInitialFrames = 0; avihdr.dwStreams = audio2In ? 3: (audioIn ? 2 : 1); avihdr.dwSuggestedBufferSize = 0; avihdr.dwWidth = xSize; avihdr.dwHeight = ySize; // Initialize file if (!fCaching) { hFile = CreateFile(szFile, GENERIC_WRITE, FILE_SHARE_READ|FILE_SHARE_WRITE, NULL, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_SEQUENTIAL_SCAN, NULL); if (INVALID_HANDLE_VALUE == hFile) throw MyWin32Error("%s: %%s", GetLastError(), szME); if (!(fastIO = new FastWriteStream(szFile, bufferSize, lChunkSize ? lChunkSize : bufferSize/2, fThreaded))) throw MyMemoryError(); } else { hFile = CreateFile(szFile, GENERIC_WRITE, FILE_SHARE_READ, NULL, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_SEQUENTIAL_SCAN | FILE_FLAG_WRITE_THROUGH, NULL); if (INVALID_HANDLE_VALUE == hFile) throw MyWin32Error("%s: %%s", GetLastError(), szME); } i64FilePosition = 0; ////////// Initialize the first 'AVI ' chunk ////////// __int64 hdrl_pos; __int64 odml_pos; DWORD dw[64]; // start RIFF chunk dw[0] = FOURCC_RIFF; dw[1] = 0; dw[2] = formtypeAVI; _writeHdr(dw, 12); // start header chunk hdrl_pos = _beginList(listtypeAVIHEADER); // write out main AVI header main_hdr_pos = _writeHdrChunk(ckidAVIMAINHDR, &avihdr, sizeof avihdr); _RPT1(0,"Main header is at %08lx\n", main_hdr_pos); // start video stream headers strl_pos = _beginList(listtypeSTREAMHEADER); // write out video stream header and format video_hdr_pos = _writeHdrChunk(ckidSTREAMHEADER, &videoOut->streamInfo, sizeof videoOut->streamInfo); _writeHdrChunk(ckidSTREAMFORMAT, videoOut->getFormat(), videoOut->getFormatLen()); _RPT1(0,"Video header is at %08lx\n", video_hdr_pos); // write out video superindex (but make it a JUNK chunk for now). if (fExtendedAVI) { memset(asie_dumb, 0, sizeof asie_dumb); video_indx_pos = _getPosition(); asi.fcc = ckidAVIPADDING; asi.cb = (sizeof asi)-8 + MAX_SUPERINDEX_ENTRIES*sizeof(_avisuperindex_entry); _writeHdr(&asi, sizeof asi); _writeHdr(asie_dumb, MAX_SUPERINDEX_ENTRIES*sizeof(_avisuperindex_entry)); } // finish video stream header _closeList(strl_pos); videoOut->streamInfo.dwSuggestedBufferSize = 0; // if there is audio... if (audioIn) { // start audio stream headers strl_pos = _beginList(listtypeSTREAMHEADER); // write out audio stream header and format audio_hdr_pos = _writeHdrChunk(ckidSTREAMHEADER, &audioOut->streamInfo, sizeof audioOut->streamInfo); audio_format_pos = _writeHdrChunk(ckidSTREAMFORMAT, audioOut->getFormat(), audioOut->getFormatLen()); _RPT1(0,"Audio header is at %08lx\n", audio_hdr_pos); // write out audio superindex (but make it a JUNK chunk for now). if (fExtendedAVI) { audio_indx_pos = _getPosition(); asi.fcc = ckidAVIPADDING; asi.cb = (sizeof asi)-8 + MAX_SUPERINDEX_ENTRIES*sizeof(_avisuperindex_entry); _writeHdr(&asi, sizeof asi); _writeHdr(asie_dumb, MAX_SUPERINDEX_ENTRIES*sizeof(_avisuperindex_entry)); } // finish audio stream header _closeList(strl_pos); audioOut->streamInfo.dwSuggestedBufferSize = 0; } // if there is a second audio... if (audio2In) { // start audio stream headers strl_pos = _beginList(listtypeSTREAMHEADER); // write out audio stream header and format audio2_hdr_pos = _writeHdrChunk(ckidSTREAMHEADER, &audio2Out->streamInfo, sizeof audio2Out->streamInfo); audio2_format_pos = _writeHdrChunk(ckidSTREAMFORMAT, audio2Out->getFormat(), audio2Out->getFormatLen()); _RPT1(0,"Audio2 header is at %08lx\n", audio2_hdr_pos); // write out audio superindex (but make it a JUNK chunk for now). if (fExtendedAVI) { audio2_indx_pos = _getPosition(); asi.fcc = ckidAVIPADDING; asi.cb = (sizeof asi)-8 + MAX_SUPERINDEX_ENTRIES*sizeof(_avisuperindex_entry); _writeHdr(&asi, sizeof asi); _writeHdr(asie_dumb, MAX_SUPERINDEX_ENTRIES*sizeof(_avisuperindex_entry)); } // finish audio stream header _closeList(strl_pos); audio2Out->streamInfo.dwSuggestedBufferSize = 0; } // write out dmlh header (indicates real # of frames) if (fExtendedAVI) { odml_pos = _beginList('lmdo'); memset(dw, 0, sizeof dw); dmlh_pos = _writeHdrChunk('hlmd', dw, 62*4); _closeList(odml_pos); } // write out segment hint block if (pSegmentHint) seghint_pos = _writeHdrChunk('mges', pSegmentHint, cbSegmentHint); _closeList(hdrl_pos); // _flushHdr(); // pad out to a multiple of 2048 bytes // // WARNING: ActiveMovie/WMP can't handle a trailing JUNK chunk in hdrl // if an extended index is in use. It says the file format // is invalid! { char *s; long pad; pad = (2048 - ((_getPosition()+8)&2047))&2047; if (pad) { if (!(s = (char *)allocmem(pad))) return FALSE; memset(s,0,pad); if (pad > 80) sprintf(s, "VirtualDub build %d/%s", version_num, #ifdef _DEBUG "debug" #else "release" #endif ); _writeHdrChunk(ckidAVIPADDING, s, pad); freemem(s); } // // If we are using a fast path, sync the fast path to the slow path // if (fastIO) // fastIO->Seek(i64FilePosition); } if (fastIO) // fastIO->FlushStart(); fastIO->Put(pHeaderBlock, nHeaderLen); else _flushHdr(); // If we're using the fast path, we're aligned to a sector boundary. // Write out the 12 header bytes. _openXblock(); { DWORD dwLo, dwHi; dwLo = GetFileSize(hFile, &dwHi); if (dwLo != 0xFFFFFFFF || GetLastError()==NO_ERROR) i64EndOfFile = dwLo | ((__int64)dwHi << 32); else i64EndOfFile = 0; } fInitComplete = true; return TRUE; }
void VDFileAsyncNT::ThreadRun() { int requestHead = 0; int requestTail = 0; int requestCount = mBlockCount; uint32 pendingLevel = 0; uint32 readOffset = 0; bool bPreemptiveExtend = mbPreemptiveExtend; sint64 currentSize; try { if (!VDGetFileSizeW32(mhFileFast, currentSize)) throw MyWin32Error("I/O error on file \"%s\": %%s", GetLastError(), mFilename.c_str()); for(;;) { int state = mState; if (state == kStateAbort) { typedef BOOL (WINAPI *tpCancelIo)(HANDLE); static const tpCancelIo pCancelIo = (tpCancelIo)GetProcAddress(GetModuleHandle(L"kernel32"), "CancelIo"); pCancelIo(mhFileFast); // Wait for any pending blocks to complete. for(int i=0; i<requestCount; ++i) { VDFileAsyncNTBuffer& buf = mpBlocks[i]; if (buf.mbActive) { WaitForSingleObject(buf.hEvent, INFINITE); buf.mbActive = false; } } break; } uint32 actual = mBufferLevel - pendingLevel; VDASSERT((int)actual >= 0); if (readOffset + actual > mBufferSize) actual = mBufferSize - readOffset; if (actual < mBlockSize) { if (state == kStateNormal || actual < mSectorSize) { // check for blocks that have completed bool blocksCompleted = false; for(;;) { VDFileAsyncNTBuffer& buf = mpBlocks[requestTail]; if (!buf.mbActive) { if (state == kStateFlush) goto all_done; if (!blocksCompleted) { // wait for further writes mWriteOccurred.wait(); } break; } if (buf.mbPending) { HANDLE h[2] = {buf.hEvent, mWriteOccurred.getHandle()}; DWORD waitResult = WaitForMultipleObjects(2, h, FALSE, INFINITE); if (waitResult == WAIT_OBJECT_0+1) // write pending break; DWORD dwActual; if (!GetOverlappedResult(mhFileFast, &buf, &dwActual, TRUE)) throw MyWin32Error("Write error occurred on file \"%s\": %%s", GetLastError(), mFilename.c_str()); } buf.mbActive = false; blocksCompleted = true; if (++requestTail >= requestCount) requestTail = 0; mBufferLevel -= buf.mLength; pendingLevel -= buf.mLength; VDASSERT((int)mBufferLevel >= 0); VDASSERT((int)pendingLevel >= 0); mReadOccurred.signal(); } continue; } VDASSERT(state == kStateFlush); actual &= ~(mSectorSize-1); VDASSERT(actual > 0); } else { actual = mBlockSize; if (bPreemptiveExtend) { sint64 checkpt = mFastPointer + mBlockSize + mBufferSize; if (checkpt > currentSize) { currentSize += mBufferSize; if (currentSize < checkpt) currentSize = checkpt; if (!VDSetFilePointerW32(mhFileFast, currentSize, FILE_BEGIN) || !SetEndOfFile(mhFileFast)) mbPreemptiveExtend = bPreemptiveExtend = false; } } } // Issue a write to OS VDFileAsyncNTBuffer& buf = mpBlocks[requestHead]; VDASSERT(!buf.mbActive); DWORD dwActual; buf.Offset = (DWORD)mFastPointer; buf.OffsetHigh = (DWORD)((uint64)mFastPointer >> 32); buf.Internal = 0; buf.InternalHigh = 0; buf.mLength = actual; buf.mbPending = false; if (!WriteFile(mhFileFast, &mBuffer[readOffset], actual, &dwActual, &buf)) { if (GetLastError() != ERROR_IO_PENDING) throw MyWin32Error("Write error occurred on file \"%s\": %%s", GetLastError(), mFilename.c_str()); buf.mbPending = true; } buf.mbActive = true; pendingLevel += actual; VDASSERT(pendingLevel <= (uint32)mBufferLevel); readOffset += actual; VDASSERT(readOffset <= mBufferSize); if (readOffset >= mBufferSize) readOffset = 0; mFastPointer += actual; if (++requestHead >= requestCount) requestHead = 0; } all_done: ; } catch(MyError& e) { MyError *p = new MyError; p->TransferFrom(e); delete mpError.xchg(p); mReadOccurred.signal(); } }
void VDFileAsyncNT::Seek(sint64 pos) { if (!SeekNT(pos)) throw MyWin32Error("I/O error on file \"%s\": %%s", GetLastError(), mFilename.c_str()); }
void VDFileAsyncNT::Truncate(sint64 pos) { Seek(pos); if (!SetEndOfFile(mhFileSlow)) throw MyWin32Error("I/O error on file \"%s\": %%s", GetLastError(), mFilename.c_str()); }
void VDFileAsync9x::ThreadRun() { bool bPreemptiveExtend = mbPreemptiveExtend; sint64 currentSize; sint64 pos = 0; uint32 bufferSize = mBlockCount * mBlockSize; HANDLE hFile = mhFileFast != INVALID_HANDLE_VALUE ? mhFileFast : mhFileSlow; try { if (bPreemptiveExtend && !VDGetFileSizeW32(hFile, currentSize)) throw MyWin32Error("I/O error on file \"%s\": %%s", GetLastError(), mFilename.c_str()); for(;;) { int state = mState; if (state == kStateAbort) break; int actual; const void *p = mBuffer.LockRead(mBlockSize, actual); if ((uint32)actual < mBlockSize) { if (state == kStateNormal) { mWriteOccurred.wait(); continue; } VDASSERT(state == kStateFlush); actual &= ~(mSectorSize-1); if (!actual) break; } else { if (bPreemptiveExtend) { sint64 checkpt = pos + mBlockSize + bufferSize; if (checkpt > currentSize) { currentSize += bufferSize; if (currentSize < checkpt) currentSize = checkpt; if (!VDSetFilePointerW32(hFile, currentSize, FILE_BEGIN) || !SetEndOfFile(hFile)) mbPreemptiveExtend = bPreemptiveExtend = false; if (!VDSetFilePointerW32(hFile, pos, FILE_BEGIN)) throw MyWin32Error("Seek error occurred on file \"%s\": %%s\n", GetLastError(), mFilename.c_str()); } } } DWORD dwActual; if (!WriteFile(hFile, p, actual, &dwActual, NULL) || dwActual != actual) { DWORD dwError = GetLastError(); throw MyWin32Error("Write error occurred on file \"%s\": %%s\n", dwError, mFilename.c_str()); } pos += actual; mBuffer.UnlockRead(actual); mReadOccurred.signal(); } } catch(MyError& e) { MyError *p = new MyError; p->TransferFrom(e); delete mpError.xchg(p); mReadOccurred.signal(); } }