| 1145 | } |
| 1146 | |
| 1147 | void CDataFileWriter::Finish() |
| 1148 | { |
| 1149 | dbg_assert((bool)m_File, "File not open"); |
| 1150 | |
| 1151 | // Compress data. This takes the majority of the time when saving a datafile, |
| 1152 | // so it's delayed until the end so it can be off-loaded to another thread. |
| 1153 | for(CDataInfo &DataInfo : m_vDatas) |
| 1154 | { |
| 1155 | unsigned long CompressedSize = compressBound(DataInfo.m_UncompressedSize); |
| 1156 | DataInfo.m_pCompressedData = malloc(CompressedSize); |
| 1157 | const int Result = compress2(static_cast<Bytef *>(DataInfo.m_pCompressedData), &CompressedSize, static_cast<Bytef *>(DataInfo.m_pUncompressedData), DataInfo.m_UncompressedSize, CompressionLevelToZlib(DataInfo.m_CompressionLevel)); |
| 1158 | DataInfo.m_CompressedSize = CompressedSize; |
| 1159 | free(DataInfo.m_pUncompressedData); |
| 1160 | DataInfo.m_pUncompressedData = nullptr; |
| 1161 | dbg_assert(Result == Z_OK, "datafile zlib compression failed with error %d", Result); |
| 1162 | } |
| 1163 | |
| 1164 | // Calculate total size of items |
| 1165 | int64_t ItemSize = 0; |
| 1166 | for(const CItemInfo &ItemInfo : m_vItems) |
| 1167 | { |
| 1168 | ItemSize += ItemInfo.m_Size; |
| 1169 | ItemSize += sizeof(CDatafileItem); |
| 1170 | } |
| 1171 | |
| 1172 | // Calculate total size of data |
| 1173 | int64_t DataSize = 0; |
| 1174 | for(const CDataInfo &DataInfo : m_vDatas) |
| 1175 | { |
| 1176 | DataSize += DataInfo.m_CompressedSize; |
| 1177 | } |
| 1178 | |
| 1179 | // Calculate complete file size |
| 1180 | const int64_t TypesSize = m_ItemTypes.size() * sizeof(CDatafileItemType); |
| 1181 | const int64_t HeaderSize = sizeof(CDatafileHeader); |
| 1182 | const int64_t OffsetSize = (m_vItems.size() + m_vDatas.size() * 2) * sizeof(int); // ItemOffsets, DataOffsets, DataUncompressedSizes |
| 1183 | const int64_t SwapSize = HeaderSize + TypesSize + OffsetSize + ItemSize; |
| 1184 | const int64_t FileSize = SwapSize + DataSize; |
| 1185 | |
| 1186 | // This also ensures that SwapSize, ItemSize and DataSize are valid. |
| 1187 | dbg_assert(FileSize <= (int64_t)std::numeric_limits<int>::max(), "File size too large"); |
| 1188 | |
| 1189 | // Construct and write header |
| 1190 | { |
| 1191 | CDatafileHeader Header; |
| 1192 | Header.m_aId[0] = 'D'; |
| 1193 | Header.m_aId[1] = 'A'; |
| 1194 | Header.m_aId[2] = 'T'; |
| 1195 | Header.m_aId[3] = 'A'; |
| 1196 | Header.m_Version = 4; |
| 1197 | Header.m_Size = FileSize - Header.SizeOffset(); |
| 1198 | Header.m_Swaplen = SwapSize - Header.SizeOffset(); |
| 1199 | Header.m_NumItemTypes = m_ItemTypes.size(); |
| 1200 | Header.m_NumItems = m_vItems.size(); |
| 1201 | Header.m_NumRawData = m_vDatas.size(); |
| 1202 | Header.m_ItemSize = ItemSize; |
| 1203 | Header.m_DataSize = DataSize; |
| 1204 |
no test coverage detected