int SFileAddFile_Write(TMPQFile * hf, const void * pvData, DWORD dwSize, DWORD dwCompression) { TMPQArchive * ha; TMPQBlock * pBlock; DWORD dwSectorPosLen = 0; int nError = ERROR_SUCCESS; // Don't bother if the caller gave us zero size if(pvData == NULL || dwSize == 0) return ERROR_SUCCESS; // Get pointer to the MPQ archive pBlock = hf->pBlock; ha = hf->ha; // Allocate file buffers if(hf->pbFileSector == NULL) { nError = AllocateSectorBuffer(hf); if(nError != ERROR_SUCCESS) { hf->bErrorOccured = true; return nError; } // Allocate sector offsets if(hf->SectorOffsets == NULL) { nError = AllocateSectorOffsets(hf, false); if(nError != ERROR_SUCCESS) { hf->bErrorOccured = true; return nError; } } // Create array of sector checksums if(hf->SectorChksums == NULL && (pBlock->dwFlags & MPQ_FILE_SECTOR_CRC)) { nError = AllocateSectorChecksums(hf, false); if(nError != ERROR_SUCCESS) { hf->bErrorOccured = true; return nError; } } // Pre-save the sector offset table, just to reserve space in the file. // Note that we dont need to swap the sector positions, nor encrypt the table // at the moment, as it will be written again after writing all file sectors. if(hf->SectorOffsets != NULL) { dwSectorPosLen = hf->dwSectorCount * sizeof(DWORD); if(!FileStream_Write(ha->pStream, &hf->RawFilePos, hf->SectorOffsets, dwSectorPosLen)) nError = GetLastError(); pBlock->dwCSize += dwSectorPosLen; } } // Write the MPQ data to the file if(nError == ERROR_SUCCESS) nError = WriteDataToMpqFile(ha, hf, (LPBYTE)pvData, dwSize, dwCompression); // If it succeeded and we wrote all the file data, // we need to re-save sector offset table if((nError == ERROR_SUCCESS) && (hf->dwFilePos >= pBlock->dwFSize)) { // Finish calculating CRC32 if(hf->pCrc32 != NULL) *hf->pCrc32 = hf->dwCrc32; // Finish calculating MD5 if(hf->pMd5 != NULL) tommd5_done((hash_state *)hf->hctx, hf->pMd5->Value); // If we also have sector checksums, write them to the file if(hf->SectorChksums != NULL) WriteSectorChecksums(hf); // Now write sector offsets to the file if(hf->SectorOffsets != NULL) WriteSectorOffsets(hf); } if(nError != ERROR_SUCCESS) hf->bErrorOccured = true; return nError; }
int SFileAddFile_Write(TMPQFile * hf, const void * pvData, DWORD dwSize, DWORD dwCompression) { TMPQArchive * ha; TFileEntry * pFileEntry; int nError = ERROR_SUCCESS; // Don't bother if the caller gave us zero size if(pvData == NULL || dwSize == 0) return ERROR_SUCCESS; // Get pointer to the MPQ archive pFileEntry = hf->pFileEntry; ha = hf->ha; // Allocate file buffers if(hf->pbFileSector == NULL) { ULONGLONG RawFilePos = hf->RawFilePos; // Allocate buffer for file sector hf->nAddFileError = nError = AllocateSectorBuffer(hf); if(nError != ERROR_SUCCESS) return nError; // Allocate patch info, if the data is patch if(hf->pPatchInfo == NULL && IsIncrementalPatchFile(pvData, dwSize, &hf->dwPatchedFileSize)) { // Set the MPQ_FILE_PATCH_FILE flag hf->pFileEntry->dwFlags |= MPQ_FILE_PATCH_FILE; // Allocate the patch info hf->nAddFileError = nError = AllocatePatchInfo(hf, false); if(nError != ERROR_SUCCESS) return nError; } // Allocate sector offsets if(hf->SectorOffsets == NULL) { hf->nAddFileError = nError = AllocateSectorOffsets(hf, false); if(nError != ERROR_SUCCESS) return nError; } // Create array of sector checksums if(hf->SectorChksums == NULL && (pFileEntry->dwFlags & MPQ_FILE_SECTOR_CRC)) { hf->nAddFileError = nError = AllocateSectorChecksums(hf, false); if(nError != ERROR_SUCCESS) return nError; } // Pre-save the patch info, if any if(hf->pPatchInfo != NULL) { if(!FileStream_Write(ha->pStream, &RawFilePos, hf->pPatchInfo, hf->pPatchInfo->dwLength)) nError = GetLastError(); pFileEntry->dwCmpSize += hf->pPatchInfo->dwLength; RawFilePos += hf->pPatchInfo->dwLength; } // Pre-save the sector offset table, just to reserve space in the file. // Note that we dont need to swap the sector positions, nor encrypt the table // at the moment, as it will be written again after writing all file sectors. if(hf->SectorOffsets != NULL) { if(!FileStream_Write(ha->pStream, &RawFilePos, hf->SectorOffsets, hf->SectorOffsets[0])) nError = GetLastError(); pFileEntry->dwCmpSize += hf->SectorOffsets[0]; RawFilePos += hf->SectorOffsets[0]; } } // Write the MPQ data to the file if(nError == ERROR_SUCCESS) { // Save the first sector compression to the file structure // Note that the entire first file sector will be compressed // by compression that was passed to the first call of SFileAddFile_Write if(hf->dwFilePos == 0) hf->dwCompression0 = dwCompression; // Write the data to the MPQ nError = WriteDataToMpqFile(ha, hf, (LPBYTE)pvData, dwSize, dwCompression); } // If it succeeded and we wrote all the file data, // we need to re-save sector offset table if(nError == ERROR_SUCCESS) { if(hf->dwFilePos >= pFileEntry->dwFileSize) { // Finish calculating CRC32 hf->pFileEntry->dwCrc32 = hf->dwCrc32; // Finish calculating MD5 md5_done((hash_state *)hf->hctx, hf->pFileEntry->md5); // If we also have sector checksums, write them to the file if(hf->SectorChksums != NULL) { nError = WriteSectorChecksums(hf); } // Now write patch info if(hf->pPatchInfo != NULL) { memcpy(hf->pPatchInfo->md5, hf->pFileEntry->md5, MD5_DIGEST_SIZE); hf->pPatchInfo->dwDataSize = hf->pFileEntry->dwFileSize; hf->pFileEntry->dwFileSize = hf->dwPatchedFileSize; nError = WritePatchInfo(hf); } // Now write sector offsets to the file if(hf->SectorOffsets != NULL) { nError = WriteSectorOffsets(hf); } // Write the MD5 hashes of each file chunk, if required if(ha->pHeader->dwRawChunkSize != 0) { nError = WriteMpqDataMD5(ha->pStream, ha->MpqPos + hf->pFileEntry->ByteOffset, hf->pFileEntry->dwCmpSize, ha->pHeader->dwRawChunkSize); } } } // Store the error code from the Write File operation hf->nAddFileError = nError; return nError; }