void PrePostProcessor::JobCompleted(DownloadQueue* pDownloadQueue, PostInfo* pPostInfo) { pPostInfo->SetWorking(false); pPostInfo->SetProgressLabel(""); pPostInfo->SetStage(PostInfo::ptFinished); DeletePostThread(pPostInfo); if (IsNZBFileCompleted(pDownloadQueue, pPostInfo->GetNZBInfo(), true, false)) { // Cleaning up queue if par-check was successful or unpack was successful or // script was successful (if unpack was not performed) bool bCanCleanupQueue = pPostInfo->GetNZBInfo()->GetParStatus() == NZBInfo::psSuccess || pPostInfo->GetNZBInfo()->GetParStatus() == NZBInfo::psRepairPossible || pPostInfo->GetNZBInfo()->GetUnpackStatus() == NZBInfo::usSuccess || (pPostInfo->GetNZBInfo()->GetUnpackStatus() == NZBInfo::usNone && pPostInfo->GetNZBInfo()->GetScriptStatuses()->CalcTotalStatus() == ScriptStatus::srSuccess); if ((g_pOptions->GetParCleanupQueue() || g_pOptions->GetNzbCleanupDisk()) && bCanCleanupQueue) { if (g_pOptions->GetParCleanupQueue()) { FileInfo* pFileInfo = GetQueueGroup(pDownloadQueue, pPostInfo->GetNZBInfo()); if (pFileInfo) { info("Cleaning up download queue for %s", pPostInfo->GetNZBInfo()->GetName()); pFileInfo->GetNZBInfo()->ClearCompletedFiles(); pFileInfo->GetNZBInfo()->SetParCleanup(true); g_pQueueCoordinator->GetQueueEditor()->LockedEditEntry(pDownloadQueue, pFileInfo->GetID(), false, QueueEditor::eaGroupDelete, 0, NULL); } } if (g_pOptions->GetNzbCleanupDisk()) { DeleteQueuedFile(pPostInfo->GetNZBInfo()->GetQueuedFilename()); } } NZBCompleted(pDownloadQueue, pPostInfo->GetNZBInfo(), false); } for (PostQueue::iterator it = pDownloadQueue->GetPostQueue()->begin(); it != pDownloadQueue->GetPostQueue()->end(); it++) { if (pPostInfo == *it) { pDownloadQueue->GetPostQueue()->erase(it); break; } } delete pPostInfo; SaveQueue(pDownloadQueue); m_bHasMoreJobs = !pDownloadQueue->GetPostQueue()->empty(); }
FileInfo* QueueEditor::FindFileInfo(DownloadQueue* pDownloadQueue, int iID) { for (FileQueue::iterator it = pDownloadQueue->GetFileQueue()->begin(); it != pDownloadQueue->GetFileQueue()->end(); it++) { FileInfo* pFileInfo = *it; if (pFileInfo->GetID() == iID) { return pFileInfo; } } return NULL; }
NZBInfo* PrePostProcessor::MergeGroups(DownloadQueue* pDownloadQueue, NZBInfo* pNZBInfo) { int iAddedGroupID = 0; // merge(1): find ID of any file in new nzb-file for (FileQueue::iterator it = pDownloadQueue->GetFileQueue()->begin(); it != pDownloadQueue->GetFileQueue()->end(); it++) { FileInfo* pFileInfo = *it; if (pFileInfo->GetNZBInfo() == pNZBInfo) { iAddedGroupID = pFileInfo->GetID(); break; } } // merge(2): check if queue has other nzb-files with the same name if (iAddedGroupID > 0) { for (FileQueue::iterator it = pDownloadQueue->GetFileQueue()->begin(); it != pDownloadQueue->GetFileQueue()->end(); it++) { FileInfo* pFileInfo = *it; if (pFileInfo->GetNZBInfo() != pNZBInfo && !strcmp(pFileInfo->GetNZBInfo()->GetName(), pNZBInfo->GetName())) { // file found, do merging IDList cIDList; cIDList.push_back(pFileInfo->GetID()); cIDList.push_back(iAddedGroupID); g_pQueueCoordinator->GetQueueEditor()->LockedEditList(pDownloadQueue, &cIDList, false, QueueEditor::eaGroupMerge, 0, NULL); return pFileInfo->GetNZBInfo(); } } } return pNZBInfo; }
void PrePostProcessor::CheckPostQueue() { DownloadQueue* pDownloadQueue = g_pQueueCoordinator->LockQueue(); if (!pDownloadQueue->GetPostQueue()->empty()) { PostInfo* pPostInfo = pDownloadQueue->GetPostQueue()->front(); if (!pPostInfo->GetWorking()) { #ifndef DISABLE_PARCHECK if (pPostInfo->GetRequestParCheck() && pPostInfo->GetNZBInfo()->GetParStatus() <= NZBInfo::psSkipped && g_pOptions->GetParCheck() != Options::pcManual) { pPostInfo->GetNZBInfo()->SetParStatus(NZBInfo::psNone); pPostInfo->SetRequestParCheck(false); pPostInfo->SetStage(PostInfo::ptQueued); pPostInfo->GetNZBInfo()->GetScriptStatuses()->Clear(); DeletePostThread(pPostInfo); } else if (pPostInfo->GetRequestParCheck() && pPostInfo->GetNZBInfo()->GetParStatus() <= NZBInfo::psSkipped && g_pOptions->GetParCheck() == Options::pcManual) { pPostInfo->SetRequestParCheck(false); pPostInfo->GetNZBInfo()->SetParStatus(NZBInfo::psManual); DeletePostThread(pPostInfo); FileInfo* pFileInfo = GetQueueGroup(pDownloadQueue, pPostInfo->GetNZBInfo()); if (pFileInfo) { info("Downloading all remaining files for manual par-check for %s", pPostInfo->GetNZBInfo()->GetName()); g_pQueueCoordinator->GetQueueEditor()->LockedEditEntry(pDownloadQueue, pFileInfo->GetID(), false, QueueEditor::eaGroupResume, 0, NULL); pPostInfo->SetStage(PostInfo::ptFinished); pPostInfo->GetNZBInfo()->SetPostProcess(false); } else { info("There are no par-files remain for download for %s", pPostInfo->GetNZBInfo()->GetName()); pPostInfo->SetStage(PostInfo::ptQueued); } } else if (pPostInfo->GetRequestParRename()) { pPostInfo->GetNZBInfo()->SetRenameStatus(NZBInfo::rsNone); pPostInfo->SetRequestParRename(false); pPostInfo->SetStage(PostInfo::ptQueued); DeletePostThread(pPostInfo); } #endif if (pPostInfo->GetDeleted()) { pPostInfo->SetStage(PostInfo::ptFinished); } if (pPostInfo->GetStage() == PostInfo::ptQueued && !g_pOptions->GetPausePostProcess()) { DeletePostThread(pPostInfo); StartJob(pDownloadQueue, pPostInfo); } else if (pPostInfo->GetStage() == PostInfo::ptFinished) { UpdatePauseState(false, NULL); JobCompleted(pDownloadQueue, pPostInfo); } else if (!g_pOptions->GetPausePostProcess()) { error("Internal error: invalid state in post-processor"); } } } g_pQueueCoordinator->UnlockQueue(); }
void ListBinCommand::Execute() { SNZBListRequest ListRequest; if (!ReceiveRequest(&ListRequest, sizeof(ListRequest))) { return; } SNZBListResponse ListResponse; memset(&ListResponse, 0, sizeof(ListResponse)); ListResponse.m_MessageBase.m_iSignature = htonl(NZBMESSAGE_SIGNATURE); ListResponse.m_MessageBase.m_iStructSize = htonl(sizeof(ListResponse)); ListResponse.m_iEntrySize = htonl(sizeof(SNZBListResponseFileEntry)); ListResponse.m_bRegExValid = 0; char* buf = NULL; int bufsize = 0; if (ntohl(ListRequest.m_bFileList)) { eRemoteMatchMode eMatchMode = (eRemoteMatchMode)ntohl(ListRequest.m_iMatchMode); bool bMatchGroup = ntohl(ListRequest.m_bMatchGroup); const char* szPattern = ListRequest.m_szPattern; RegEx *pRegEx = NULL; if (eMatchMode == eRemoteMatchModeRegEx) { pRegEx = new RegEx(szPattern); ListResponse.m_bRegExValid = pRegEx->IsValid(); } // Make a data structure and copy all the elements of the list into it DownloadQueue* pDownloadQueue = g_pQueueCoordinator->LockQueue(); // calculate required buffer size for nzbs int iNrNZBEntries = pDownloadQueue->GetNZBInfoList()->size(); int iNrPPPEntries = 0; bufsize += iNrNZBEntries * sizeof(SNZBListResponseNZBEntry); for (NZBInfoList::iterator it = pDownloadQueue->GetNZBInfoList()->begin(); it != pDownloadQueue->GetNZBInfoList()->end(); it++) { NZBInfo* pNZBInfo = *it; bufsize += strlen(pNZBInfo->GetFilename()) + 1; bufsize += strlen(pNZBInfo->GetName()) + 1; bufsize += strlen(pNZBInfo->GetDestDir()) + 1; bufsize += strlen(pNZBInfo->GetCategory()) + 1; bufsize += strlen(pNZBInfo->GetQueuedFilename()) + 1; // align struct to 4-bytes, needed by ARM-processor (and may be others) bufsize += bufsize % 4 > 0 ? 4 - bufsize % 4 : 0; // calculate required buffer size for pp-parameters for (NZBParameterList::iterator it = pNZBInfo->GetParameters()->begin(); it != pNZBInfo->GetParameters()->end(); it++) { NZBParameter* pNZBParameter = *it; bufsize += sizeof(SNZBListResponsePPPEntry); bufsize += strlen(pNZBParameter->GetName()) + 1; bufsize += strlen(pNZBParameter->GetValue()) + 1; // align struct to 4-bytes, needed by ARM-processor (and may be others) bufsize += bufsize % 4 > 0 ? 4 - bufsize % 4 : 0; iNrPPPEntries++; } } // calculate required buffer size for files int iNrFileEntries = pDownloadQueue->GetFileQueue()->size(); bufsize += iNrFileEntries * sizeof(SNZBListResponseFileEntry); for (FileQueue::iterator it = pDownloadQueue->GetFileQueue()->begin(); it != pDownloadQueue->GetFileQueue()->end(); it++) { FileInfo* pFileInfo = *it; bufsize += strlen(pFileInfo->GetSubject()) + 1; bufsize += strlen(pFileInfo->GetFilename()) + 1; // align struct to 4-bytes, needed by ARM-processor (and may be others) bufsize += bufsize % 4 > 0 ? 4 - bufsize % 4 : 0; } buf = (char*) malloc(bufsize); char* bufptr = buf; // write nzb entries for (NZBInfoList::iterator it = pDownloadQueue->GetNZBInfoList()->begin(); it != pDownloadQueue->GetNZBInfoList()->end(); it++) { unsigned long iSizeHi, iSizeLo; NZBInfo* pNZBInfo = *it; SNZBListResponseNZBEntry* pListAnswer = (SNZBListResponseNZBEntry*) bufptr; Util::SplitInt64(pNZBInfo->GetSize(), &iSizeHi, &iSizeLo); pListAnswer->m_iSizeLo = htonl(iSizeLo); pListAnswer->m_iSizeHi = htonl(iSizeHi); pListAnswer->m_bMatch = htonl(bMatchGroup && (!pRegEx || pRegEx->Match(pNZBInfo->GetName()))); pListAnswer->m_iFilenameLen = htonl(strlen(pNZBInfo->GetFilename()) + 1); pListAnswer->m_iNameLen = htonl(strlen(pNZBInfo->GetName()) + 1); pListAnswer->m_iDestDirLen = htonl(strlen(pNZBInfo->GetDestDir()) + 1); pListAnswer->m_iCategoryLen = htonl(strlen(pNZBInfo->GetCategory()) + 1); pListAnswer->m_iQueuedFilenameLen = htonl(strlen(pNZBInfo->GetQueuedFilename()) + 1); bufptr += sizeof(SNZBListResponseNZBEntry); strcpy(bufptr, pNZBInfo->GetFilename()); bufptr += ntohl(pListAnswer->m_iFilenameLen); strcpy(bufptr, pNZBInfo->GetName()); bufptr += ntohl(pListAnswer->m_iNameLen); strcpy(bufptr, pNZBInfo->GetDestDir()); bufptr += ntohl(pListAnswer->m_iDestDirLen); strcpy(bufptr, pNZBInfo->GetCategory()); bufptr += ntohl(pListAnswer->m_iCategoryLen); strcpy(bufptr, pNZBInfo->GetQueuedFilename()); bufptr += ntohl(pListAnswer->m_iQueuedFilenameLen); // align struct to 4-bytes, needed by ARM-processor (and may be others) if ((size_t)bufptr % 4 > 0) { pListAnswer->m_iQueuedFilenameLen = htonl(ntohl(pListAnswer->m_iQueuedFilenameLen) + 4 - (size_t)bufptr % 4); memset(bufptr, 0, 4 - (size_t)bufptr % 4); //suppress valgrind warning "uninitialized data" bufptr += 4 - (size_t)bufptr % 4; } } // write ppp entries int iNZBIndex = 1; for (NZBInfoList::iterator it = pDownloadQueue->GetNZBInfoList()->begin(); it != pDownloadQueue->GetNZBInfoList()->end(); it++, iNZBIndex++) { NZBInfo* pNZBInfo = *it; for (NZBParameterList::iterator it = pNZBInfo->GetParameters()->begin(); it != pNZBInfo->GetParameters()->end(); it++) { NZBParameter* pNZBParameter = *it; SNZBListResponsePPPEntry* pListAnswer = (SNZBListResponsePPPEntry*) bufptr; pListAnswer->m_iNZBIndex = htonl(iNZBIndex); pListAnswer->m_iNameLen = htonl(strlen(pNZBParameter->GetName()) + 1); pListAnswer->m_iValueLen = htonl(strlen(pNZBParameter->GetValue()) + 1); bufptr += sizeof(SNZBListResponsePPPEntry); strcpy(bufptr, pNZBParameter->GetName()); bufptr += ntohl(pListAnswer->m_iNameLen); strcpy(bufptr, pNZBParameter->GetValue()); bufptr += ntohl(pListAnswer->m_iValueLen); // align struct to 4-bytes, needed by ARM-processor (and may be others) if ((size_t)bufptr % 4 > 0) { pListAnswer->m_iValueLen = htonl(ntohl(pListAnswer->m_iValueLen) + 4 - (size_t)bufptr % 4); memset(bufptr, 0, 4 - (size_t)bufptr % 4); //suppress valgrind warning "uninitialized data" bufptr += 4 - (size_t)bufptr % 4; } } } // write file entries for (FileQueue::iterator it = pDownloadQueue->GetFileQueue()->begin(); it != pDownloadQueue->GetFileQueue()->end(); it++) { unsigned long iSizeHi, iSizeLo; FileInfo* pFileInfo = *it; SNZBListResponseFileEntry* pListAnswer = (SNZBListResponseFileEntry*) bufptr; pListAnswer->m_iID = htonl(pFileInfo->GetID()); int iNZBIndex = 0; for (unsigned int i = 0; i < pDownloadQueue->GetNZBInfoList()->size(); i++) { iNZBIndex++; if (pDownloadQueue->GetNZBInfoList()->at(i) == pFileInfo->GetNZBInfo()) { break; } } pListAnswer->m_iNZBIndex = htonl(iNZBIndex); if (pRegEx && !bMatchGroup) { char szFilename[MAX_PATH]; snprintf(szFilename, sizeof(szFilename) - 1, "%s/%s", pFileInfo->GetNZBInfo()->GetName(), Util::BaseFileName(pFileInfo->GetFilename())); pListAnswer->m_bMatch = htonl(pRegEx->Match(szFilename)); } Util::SplitInt64(pFileInfo->GetSize(), &iSizeHi, &iSizeLo); pListAnswer->m_iFileSizeLo = htonl(iSizeLo); pListAnswer->m_iFileSizeHi = htonl(iSizeHi); Util::SplitInt64(pFileInfo->GetRemainingSize(), &iSizeHi, &iSizeLo); pListAnswer->m_iRemainingSizeLo = htonl(iSizeLo); pListAnswer->m_iRemainingSizeHi = htonl(iSizeHi); pListAnswer->m_bFilenameConfirmed = htonl(pFileInfo->GetFilenameConfirmed()); pListAnswer->m_bPaused = htonl(pFileInfo->GetPaused()); pListAnswer->m_iActiveDownloads = htonl(pFileInfo->GetActiveDownloads()); pListAnswer->m_iPriority = htonl(pFileInfo->GetPriority()); pListAnswer->m_iSubjectLen = htonl(strlen(pFileInfo->GetSubject()) + 1); pListAnswer->m_iFilenameLen = htonl(strlen(pFileInfo->GetFilename()) + 1); bufptr += sizeof(SNZBListResponseFileEntry); strcpy(bufptr, pFileInfo->GetSubject()); bufptr += ntohl(pListAnswer->m_iSubjectLen); strcpy(bufptr, pFileInfo->GetFilename()); bufptr += ntohl(pListAnswer->m_iFilenameLen); // align struct to 4-bytes, needed by ARM-processor (and may be others) if ((size_t)bufptr % 4 > 0) { pListAnswer->m_iFilenameLen = htonl(ntohl(pListAnswer->m_iFilenameLen) + 4 - (size_t)bufptr % 4); memset(bufptr, 0, 4 - (size_t)bufptr % 4); //suppress valgrind warning "uninitialized data" bufptr += 4 - (size_t)bufptr % 4; } } g_pQueueCoordinator->UnlockQueue(); if (pRegEx) { delete pRegEx; } ListResponse.m_iNrTrailingNZBEntries = htonl(iNrNZBEntries); ListResponse.m_iNrTrailingPPPEntries = htonl(iNrPPPEntries); ListResponse.m_iNrTrailingFileEntries = htonl(iNrFileEntries); ListResponse.m_iTrailingDataLength = htonl(bufsize); } if (htonl(ListRequest.m_bServerState)) { unsigned long iSizeHi, iSizeLo; ListResponse.m_iDownloadRate = htonl((int)(g_pQueueCoordinator->CalcCurrentDownloadSpeed() * 1024)); Util::SplitInt64(g_pQueueCoordinator->CalcRemainingSize(), &iSizeHi, &iSizeLo); ListResponse.m_iRemainingSizeHi = htonl(iSizeHi); ListResponse.m_iRemainingSizeLo = htonl(iSizeLo); ListResponse.m_iDownloadLimit = htonl((int)(g_pOptions->GetDownloadRate() * 1024)); ListResponse.m_bDownloadPaused = htonl(g_pOptions->GetPauseDownload()); ListResponse.m_bDownload2Paused = htonl(g_pOptions->GetPauseDownload2()); ListResponse.m_bPostPaused = htonl(g_pOptions->GetPausePostProcess()); ListResponse.m_bScanPaused = htonl(g_pOptions->GetPauseScan()); ListResponse.m_iThreadCount = htonl(Thread::GetThreadCount() - 1); // not counting itself PostQueue* pPostQueue = g_pQueueCoordinator->LockQueue()->GetPostQueue(); ListResponse.m_iPostJobCount = htonl(pPostQueue->size()); g_pQueueCoordinator->UnlockQueue(); int iUpTimeSec, iDnTimeSec; long long iAllBytes; bool bStandBy; g_pQueueCoordinator->CalcStat(&iUpTimeSec, &iDnTimeSec, &iAllBytes, &bStandBy); ListResponse.m_iUpTimeSec = htonl(iUpTimeSec); ListResponse.m_iDownloadTimeSec = htonl(iDnTimeSec); ListResponse.m_bDownloadStandBy = htonl(bStandBy); Util::SplitInt64(iAllBytes, &iSizeHi, &iSizeLo); ListResponse.m_iDownloadedBytesHi = htonl(iSizeHi); ListResponse.m_iDownloadedBytesLo = htonl(iSizeLo); } // Send the request answer send(m_iSocket, (char*) &ListResponse, sizeof(ListResponse), 0); // Send the data if (bufsize > 0) { send(m_iSocket, buf, bufsize, 0); } if (buf) { free(buf); } }
bool QueueEditor::BuildIDListFromNameList(DownloadQueue* pDownloadQueue, IDList* pIDList, NameList* pNameList, EMatchMode eMatchMode, EEditAction eAction) { #ifndef HAVE_REGEX_H if (eMatchMode == mmRegEx) { return false; } #endif std::set<int> uniqueIDs; for (NameList::iterator it = pNameList->begin(); it != pNameList->end(); it++) { const char* szName = *it; RegEx *pRegEx = NULL; if (eMatchMode == mmRegEx) { pRegEx = new RegEx(szName); if (!pRegEx->IsValid()) { delete pRegEx; return false; } } bool bFound = false; for (FileQueue::iterator it2 = pDownloadQueue->GetFileQueue()->begin(); it2 != pDownloadQueue->GetFileQueue()->end(); it2++) { FileInfo* pFileInfo = *it2; if (eAction < eaGroupMoveOffset) { // file action char szFilename[MAX_PATH]; snprintf(szFilename, sizeof(szFilename) - 1, "%s/%s", pFileInfo->GetNZBInfo()->GetName(), Util::BaseFileName(pFileInfo->GetFilename())); if (((!pRegEx && !strcmp(szFilename, szName)) || (pRegEx && pRegEx->Match(szFilename))) && (uniqueIDs.find(pFileInfo->GetID()) == uniqueIDs.end())) { uniqueIDs.insert(pFileInfo->GetID()); pIDList->push_back(pFileInfo->GetID()); bFound = true; } } else { // group action const char *szFilename = pFileInfo->GetNZBInfo()->GetName(); if (((!pRegEx && !strcmp(szFilename, szName)) || (pRegEx && pRegEx->Match(szFilename))) && (uniqueIDs.find(pFileInfo->GetNZBInfo()->GetID()) == uniqueIDs.end())) { uniqueIDs.insert(pFileInfo->GetNZBInfo()->GetID()); pIDList->push_back(pFileInfo->GetID()); bFound = true; } } } if (pRegEx) { delete pRegEx; } if (!bFound && (eMatchMode == mmName)) { return false; } } return true; }
void QueueEditor::PrepareList(DownloadQueue* pDownloadQueue, ItemList* pItemList, IDList* pIDList, bool bSmartOrder, EEditAction EEditAction, int iOffset) { if (EEditAction == eaFileMoveTop) { iOffset = -MAX_ID; } else if (EEditAction == eaFileMoveBottom) { iOffset = MAX_ID; } pItemList->reserve(pIDList->size()); if (bSmartOrder && iOffset != 0 && (EEditAction == eaFileMoveOffset || EEditAction == eaFileMoveTop || EEditAction == eaFileMoveBottom)) { //add IDs to list in order they currently have in download queue int iLastDestPos = -1; int iStart, iEnd, iStep; if (iOffset < 0) { iStart = 0; iEnd = pDownloadQueue->GetFileQueue()->size(); iStep = 1; } else { iStart = pDownloadQueue->GetFileQueue()->size() - 1; iEnd = -1; iStep = -1; } for (int iIndex = iStart; iIndex != iEnd; iIndex += iStep) { FileInfo* pFileInfo = pDownloadQueue->GetFileQueue()->at(iIndex); int iID = pFileInfo->GetID(); for (IDList::iterator it = pIDList->begin(); it != pIDList->end(); it++) { if (iID == *it) { int iWorkOffset = iOffset; int iDestPos = iIndex + iWorkOffset; if (iLastDestPos == -1) { if (iDestPos < 0) { iWorkOffset = -iIndex; } else if (iDestPos > int(pDownloadQueue->GetFileQueue()->size()) - 1) { iWorkOffset = int(pDownloadQueue->GetFileQueue()->size()) - 1 - iIndex; } } else { if (iWorkOffset < 0 && iDestPos <= iLastDestPos) { iWorkOffset = iLastDestPos - iIndex + 1; } else if (iWorkOffset > 0 && iDestPos >= iLastDestPos) { iWorkOffset = iLastDestPos - iIndex - 1; } } iLastDestPos = iIndex + iWorkOffset; pItemList->push_back(new EditItem(pFileInfo, iWorkOffset)); break; } } } } else { // check ID range int iMaxID = 0; int iMinID = MAX_ID; for (FileQueue::iterator it = pDownloadQueue->GetFileQueue()->begin(); it != pDownloadQueue->GetFileQueue()->end(); it++) { FileInfo* pFileInfo = *it; int ID = pFileInfo->GetID(); if (ID > iMaxID) { iMaxID = ID; } if (ID < iMinID) { iMinID = ID; } } //add IDs to list in order they were transmitted in command for (IDList::iterator it = pIDList->begin(); it != pIDList->end(); it++) { int iID = *it; if (iMinID <= iID && iID <= iMaxID) { FileInfo* pFileInfo = FindFileInfo(pDownloadQueue, iID); if (pFileInfo) { pItemList->push_back(new EditItem(pFileInfo, iOffset)); } } } } }