• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

PredatorCZ / PreCore / 513

09 Apr 2024 03:03PM UTC coverage: 54.2% (-0.04%) from 54.243%
513

push

github

PredatorCZ
print error on signal

0 of 2 new or added lines in 1 file covered. (0.0%)

93 existing lines in 2 files now uncovered.

4142 of 7642 relevant lines covered (54.2%)

8773.33 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

0.0
/src/app/out_context.cpp
1
/*  Spike is universal dedicated module handler
2
    This souce contains data output context
3

4
    Copyright 2021-2023 Lukas Cone
5

6
    Licensed under the Apache License, Version 2.0 (the "License");
7
    you may not use this file except in compliance with the License.
8
    You may obtain a copy of the License at
9

10
        http://www.apache.org/licenses/LICENSE-2.0
11

12
    Unless required by applicable law or agreed to in writing, software
13
    distributed under the License is distributed on an "AS IS" BASIS,
14
    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15
    See the License for the specific language governing permissions and
16
    limitations under the License.
17
*/
18

19
#include "spike/app/out_context.hpp"
20
#include "spike/app/console.hpp"
21
#include "spike/app/texel.hpp"
22
#include "spike/crypto/crc32.hpp"
23
#include "spike/format/ZIP_istream.inl"
24
#include "spike/format/ZIP_ostream.inl"
25
#include "spike/io/binreader.hpp"
26
#include "spike/io/fileinfo.hpp"
27
#include "spike/io/stat.hpp"
28
#include <chrono>
29
#include <mutex>
30

31
void ZIPExtactContext::FinishZIP(cache_begin_cb cacheBeginCB) {
×
32
  FinishFile(true);
×
33

34
  auto entriesStr = std::move(entriesStream).str();
35
  bool forcex64 = false;
×
36
  const size_t dirOffset = records.Tell();
37
  size_t dirSize = entriesStr.size();
38

39
  auto SafeCast = [&](auto &where, auto &&what) {
40
    const uint64 limit =
41
        std::numeric_limits<std::decay_t<decltype(where)>>::max();
42
    if (what >= limit) {
×
43
      forcex64 = true;
×
44
      where = limit;
×
45
    } else {
46
      where = what;
×
47
    }
48
  };
49

50
  ZIPCentralDir zCentral{};
×
51
  zCentral.id = ZIPCentralDir::ID;
×
52
  SafeCast(zCentral.numDirEntries, numEntries);
53
  SafeCast(zCentral.numDiskEntries, numEntries);
54
  SafeCast(zCentral.dirOffset, dirOffset);
55

56
  records.WriteContainer(entriesStr);
57
  es::Dispose(entriesStr);
58

59
  if (cache) {
×
60
    records.Write<uint16>(0x4353);
×
61
    records.Write<uint16>(sizeof(CacheBaseHeader));
×
62
    cache->meta.zipCheckupOffset = records.Tell();
×
63
    records.Write(cache->meta);
×
64
    dirSize += sizeof(CacheBaseHeader) + 4;
×
65
  }
66

67
  SafeCast(zCentral.dirSize, dirSize);
68

69
  if (forcex64) {
×
70
    ZIP64CentralDir zCentral64{};
×
71
    zCentral64.id = ZIP64CentralDir::ID;
×
72
    zCentral64.madeBy = 10;
×
73
    zCentral64.extractVersion = 10;
×
74
    zCentral64.dirRecord = 0x2C;
×
75
    zCentral64.numDiskEntries = numEntries;
×
76
    zCentral64.numDirEntries = numEntries;
×
77
    zCentral64.dirSize = dirSize;
×
78
    zCentral64.dirOffset = dirOffset;
×
79

80
    const size_t centralOffset = records.Tell();
81
    records.Write(zCentral64);
×
82

83
    ZIP64CentralDirLocator zLoca{};
×
84
    zLoca.id = ZIP64CentralDirLocator::ID;
×
85
    zLoca.centralDirOffset = centralOffset;
×
86
    records.Write(zLoca);
87
  }
88

89
  records.Write(zCentral);
UNCOV
90
  records.BaseStream().flush();
×
91

92
  if (cache) {
×
93
    cacheBeginCB();
×
94
    cache->meta.zipSize = records.Tell();
×
95
    BinWritter cacheWr(outputFile + ".cache");
×
96
    cache->WaitAndWrite(cacheWr);
×
97
    records.Seek(cache->meta.zipCheckupOffset);
×
UNCOV
98
    records.Write(cache->meta);
×
99
  }
100
}
101

UNCOV
102
void ZIPExtactContext::FinishFile(bool final) {
×
103
  auto SafeCast = [&](auto &where, auto &&what) {
104
    const uint64 limit =
105
        std::numeric_limits<std::decay_t<decltype(where)>>::max();
106
    bool forcex64 = false;
107

UNCOV
108
    if (what >= limit) {
×
109
      forcex64 = true;
UNCOV
110
      where = limit;
×
111
    } else {
UNCOV
112
      where = what;
×
113
    }
114

115
    return forcex64;
116
  };
117

118
  const bool useLocalExtendedData =
119
      SafeCast(zLocalFile.uncompressedSize, curFileSize);
UNCOV
120
  zLocalFile.compressedSize = zLocalFile.uncompressedSize;
×
121

UNCOV
122
  if (useLocalExtendedData) {
×
123
    ZIP64Extra extra;
124
    extra.compressedSize = curFileSize;
×
125
    extra.uncompressedSize = curFileSize;
×
126
    records.Write(extra);
×
UNCOV
127
    zLocalFile.extraFieldSize = 20;
×
128
  }
129

UNCOV
130
  numEntries++;
×
131
  records.Push();
132
  records.Seek(curLocalFileOffset);
×
UNCOV
133
  records.Write(zLocalFile);
×
134
  const size_t fileDataBegin =
UNCOV
135
      records.Tell() + zLocalFile.extraFieldSize + zLocalFile.fileNameSize;
×
136

137
  if (cache) {
×
138
    cache->AddFile(curFileName, fileDataBegin, curFileSize);
×
139
    cache->meta.zipCRC = crc32b(
×
UNCOV
140
        cache->meta.zipCRC, reinterpret_cast<const char *>(&zLocalFile.crc), 4);
×
141
  } else {
UNCOV
142
    fileOffsets.push_back(fileDataBegin);
×
143
  }
144

145
  records.Pop();
146

147
  ZIPFile zFile{};
×
148
  zFile.id = ZIPFile::ID;
×
149
  zFile.madeBy = 10;
×
150
  zFile.extractVersion = 10;
×
151
  zFile.lastModFileDate = zLocalFile.lastModFileDate;
×
UNCOV
152
  zFile.lastModFileTime = zLocalFile.lastModFileTime;
×
153
  zFile.compression = ZIPCompressionMethod::Store;
154
  zFile.compressedSize = zLocalFile.compressedSize;
×
155
  zFile.uncompressedSize = zLocalFile.uncompressedSize;
×
156
  zFile.fileNameSize = zLocalFile.fileNameSize;
×
UNCOV
157
  zFile.crc = zLocalFile.crc;
×
158
  const bool useFileExtendedData =
159
      SafeCast(zFile.localHeaderOffset, curLocalFileOffset);
160

UNCOV
161
  const bool useFileExtra = useFileExtendedData || useLocalExtendedData;
×
162
  ZIP64Extra extra;
163

164
  if (useFileExtra) {
×
UNCOV
165
    zFile.extraFieldSize = 4;
×
166

167
    if (useLocalExtendedData) {
×
168
      extra.uncompressedSize = curFileSize;
×
169
      extra.compressedSize = curFileSize;
×
UNCOV
170
      zFile.extraFieldSize += 16;
×
171
    }
172

173
    if (useFileExtendedData) {
×
174
      extra.localHeaderOffset = curLocalFileOffset;
×
UNCOV
175
      zFile.extraFieldSize += 8;
×
176
    }
177
  }
178

179
  if (final && cache) {
×
UNCOV
180
    zFile.extraFieldSize += sizeof(CacheBaseHeader) + 4;
×
181
  }
182

UNCOV
183
  entries.Write(zFile);
×
184
  entries.WriteContainer(prefixPath);
185
  entries.WriteContainer(curFileName);
186

UNCOV
187
  if (useFileExtra) {
×
188
    entries.Write(extra);
189
  }
190
}
191

192
inline std::tm localtime(std::time_t t) {
193
#ifdef _MSC_VER
194
  return *std::localtime(&t);
195
#else
196
  std::tm temp;
UNCOV
197
  localtime_r(&t, &temp);
×
198
  return temp;
199
#endif
200
}
201

202
void ZIPExtactContext::NewFile(const std::string &path) {
×
203
  if (path.empty()) [[unlikely]] {
×
UNCOV
204
    throw std::runtime_error("NewFile path is empty");
×
205
  }
UNCOV
206
  AFileInfo pathInfo(path);
×
207
  auto pathSv = pathInfo.GetFullPath();
208
  if (!curFileName.empty()) {
×
UNCOV
209
    FinishFile();
×
210
  }
211

212
  time_t curTime =
213
      std::chrono::system_clock::to_time_t(std::chrono::system_clock::now());
×
UNCOV
214
  std::tm ts = localtime(curTime);
×
215

216
  struct {
217
    uint16 day : 5, month : 4, year : 7;
UNCOV
218
  } dosDate{uint16(ts.tm_mday), uint16(ts.tm_mon + 1), uint16(ts.tm_year - 80)};
×
219

220
  struct {
221
    uint16 second : 5, minute : 6, hour : 5;
UNCOV
222
  } dosTime{uint16(ts.tm_sec / 2), uint16(ts.tm_min), uint16(ts.tm_hour)};
×
223

224
  zLocalFile.lastModFileDate = reinterpret_cast<uint16 &>(dosDate);
×
225
  zLocalFile.lastModFileTime = reinterpret_cast<uint16 &>(dosTime);
×
226
  zLocalFile.compression = ZIPCompressionMethod::Store;
×
227
  zLocalFile.fileNameSize = prefixPath.size() + pathSv.size();
×
228
  zLocalFile.crc = 0;
×
UNCOV
229
  curFileSize = 0;
×
230

231
  curFileName = pathSv;
×
232
  curLocalFileOffset = records.Tell();
×
UNCOV
233
  records.Write(zLocalFile);
×
234
  records.WriteContainer(prefixPath);
235
  records.WriteContainer(pathSv);
236

UNCOV
237
  if (forEachFile) {
×
238
    forEachFile();
239
  }
240
}
241

242
void ZIPExtactContext::SendData(std::string_view data) {
×
243
  curFileSize += data.size();
×
UNCOV
244
  zLocalFile.crc = crc32b(zLocalFile.crc, data.data(), data.size());
×
245
  records.WriteContainer(data);
246
}
247

UNCOV
248
bool ZIPExtactContext::RequiresFolders() const { return false; }
×
249

250
void ZIPExtactContext::AddFolderPath(const std::string &) {
×
251
  throw std::logic_error(
×
UNCOV
252
      "AddFolderPath not supported, use RequiresFolders to check.");
×
253
}
254

255
void ZIPExtactContext::GenerateFolders() {
×
256
  throw std::logic_error(
×
UNCOV
257
      "GenerateFolders not supported, use RequiresFolders to check.");
×
258
}
259

UNCOV
260
NewTexelContext *ZIPExtactContext::NewImage(const std::string &path,
×
261
                                            NewTexelContextCreate ctx) {
UNCOV
262
  auto newCtx = CreateTexelContext(ctx, this, path);
×
263

UNCOV
264
  if (texelContext) {
×
265
    static_cast<NewTexelContextImpl *>(texelContext.get())->Finish();
266
  }
267

268
  texelContext = std::move(newCtx);
269

UNCOV
270
  return texelContext.get();
×
271
}
272

273
void IOExtractContext::NewFile(const std::string &path) {
×
274
  Close_();
×
275
  if (path.empty()) [[unlikely]] {
×
UNCOV
276
    throw std::runtime_error("NewFile path is empty");
×
277
  }
278
  AFileInfo cfleWrap(path);
×
279
  std::string cfle(cfleWrap.GetFullPath());
×
UNCOV
280
  Open(outDir + cfle);
×
281

UNCOV
282
  if (forEachFile) {
×
283
    forEachFile();
284
  }
285
}
286

UNCOV
287
void IOExtractContext::SendData(std::string_view data) { WriteContainer(data); }
×
288

UNCOV
289
bool IOExtractContext::RequiresFolders() const { return true; }
×
290

291
void IOExtractContext::AddFolderPath(const std::string &path) {
×
UNCOV
292
  AFileInfo cfleWrap(path);
×
293
  auto cfle = cfleWrap.GetFullPath();
294

295
  for (auto it = cfle.begin(); it != cfle.end(); it++) {
×
296
    if (*it == '/') {
×
UNCOV
297
      folderTree.emplace(cfle.begin(), it);
×
298
    }
299
  }
300

301
  folderTree.emplace(path);
302
}
303

304
void IOExtractContext::GenerateFolders() {
×
305
  for (auto &f : folderTree) {
×
UNCOV
306
    auto genFolder = outDir + f;
×
307
    es::mkdir(genFolder);
308
  }
309

310
  folderTree.clear();
311
}
312

UNCOV
313
NewTexelContext *IOExtractContext::NewImage(const std::string &path,
×
314
                                            NewTexelContextCreate ctx) {
UNCOV
315
  auto newCtx = CreateTexelContext(ctx, this, path);
×
316

UNCOV
317
  if (texelContext) {
×
318
    static_cast<NewTexelContextImpl *>(texelContext.get())->Finish();
319
  }
320

321
  texelContext = std::move(newCtx);
322

UNCOV
323
  return texelContext.get();
×
324
}
325

326
static std::mutex ZIPLock;
327

328
void ZIPMerger::Merge(ZIPExtactContext &other, const std::string &recordsFile) {
×
329
  if (!other.curFileName.empty()) {
×
UNCOV
330
    other.FinishFile();
×
331
  }
332

UNCOV
333
  BinReaderRef localEntries(other.entriesStream);
×
334
  char buffer[0x80000];
335
  std::lock_guard<std::mutex> guard(ZIPLock);
336
  const size_t filesSize = records.Tell();
337

UNCOV
338
  numEntries += other.numEntries;
×
339

UNCOV
340
  for (auto o : other.fileOffsets) {
×
341
    ZIPFile zFile;
UNCOV
342
    localEntries.Read(zFile);
×
343

344
    const size_t localHeaderOffset = zFile.localHeaderOffset;
×
345
    const bool newExtraField = zFile.localHeaderOffset < 0xffffffff &&
×
UNCOV
346
                               localHeaderOffset + filesSize >= 0xffffffff;
×
347
    bool newExtra = false;
348

349
    if (newExtraField) {
UNCOV
350
      zFile.localHeaderOffset = 0xffffffff;
×
351

352
      if (!zFile.extraFieldSize) {
×
UNCOV
353
        zFile.extraFieldSize = 12;
×
354
        newExtra = true;
355
      } else {
UNCOV
356
        zFile.extraFieldSize += 8;
×
357
      }
358
    }
359

360
    if (zFile.localHeaderOffset < 0xffffffff) {
×
UNCOV
361
      zFile.localHeaderOffset += filesSize;
×
362
    }
363

364
    entries.Write(zFile);
×
365
    localEntries.ReadBuffer(buffer, zFile.fileNameSize);
×
366
    cache.AddFile({buffer, zFile.fileNameSize}, o + filesSize,
×
367
                  zFile.uncompressedSize);
×
UNCOV
368
    cache.meta.zipCRC = crc32b(cache.meta.zipCRC,
×
369
                               reinterpret_cast<const char *>(&zFile.crc), 4);
UNCOV
370
    entries.WriteBuffer(buffer, zFile.fileNameSize);
×
371

372
    if (newExtra) {
×
373
      ZIP64Extra extra{};
×
UNCOV
374
      extra.localHeaderOffset = localHeaderOffset + filesSize;
×
375
      entries.Write(extra);
376
    } else if (zFile.extraFieldSize) {
×
UNCOV
377
      ZIP64Extra extra{};
×
378
      localEntries.Read(extra.id);
379
      localEntries.Read(extra.size);
380

UNCOV
381
      if (zFile.compressedSize == 0xffffffff) {
×
382
        localEntries.Read(extra.compressedSize);
383
        localEntries.Read(extra.uncompressedSize);
384
      }
385

386
      if (zFile.localHeaderOffset == 0xffffffff) {
×
387
        if (newExtraField) {
×
UNCOV
388
          extra.localHeaderOffset = localHeaderOffset + filesSize;
×
389
        } else {
390
          localEntries.Read(extra.localHeaderOffset);
UNCOV
391
          extra.localHeaderOffset += filesSize;
×
392
        }
393
      }
394

395
      entries.Write(extra);
396
    }
397
  }
398

UNCOV
399
  es::Dispose(other.entriesStream);
×
400

401
  const size_t recordsSize = other.records.Tell();
402
  es::Dispose(other.records);
×
403
  BinReader rd(recordsFile);
×
404
  const size_t numBlocks = recordsSize / sizeof(buffer);
×
UNCOV
405
  const size_t restBytes = recordsSize % sizeof(buffer);
×
406

UNCOV
407
  for (size_t b = 0; b < numBlocks; b++) {
×
408
    rd.ReadBuffer(buffer, sizeof(buffer));
409
    records.WriteBuffer(buffer, sizeof(buffer));
410
  }
411

UNCOV
412
  if (restBytes) {
×
413
    rd.ReadBuffer(buffer, restBytes);
414
    records.WriteBuffer(buffer, restBytes);
415
  }
416
}
417

418
void ZIPMerger::FinishMerge(cache_begin_cb cacheBeginCB) {
×
419
  size_t entriesSize = entries.Tell();
×
UNCOV
420
  es::Dispose(entries);
×
421
  char buffer[0x80000];
422
  BinReader rd(entriesFile);
×
423
  const size_t numBlocks = entriesSize / sizeof(buffer);
×
424
  const size_t restBytes = entriesSize % sizeof(buffer);
×
UNCOV
425
  bool forcex64 = false;
×
426
  const size_t dirOffset = records.Tell();
427

428
  auto SafeCast = [&](auto &where, auto &&what) {
429
    const uint64 limit =
430
        std::numeric_limits<std::decay_t<decltype(where)>>::max();
431
    if (what >= limit) {
×
432
      forcex64 = true;
×
UNCOV
433
      where = limit;
×
434
    } else {
UNCOV
435
      where = what;
×
436
    }
437
  };
438

439
  ZIPCentralDir zCentral{};
×
UNCOV
440
  zCentral.id = ZIPCentralDir::ID;
×
441
  SafeCast(zCentral.numDirEntries, numEntries);
442
  SafeCast(zCentral.numDiskEntries, numEntries);
443
  SafeCast(zCentral.dirOffset, dirOffset);
444

UNCOV
445
  for (size_t b = 0; b < numBlocks; b++) {
×
446
    rd.ReadBuffer(buffer, sizeof(buffer));
447
    records.WriteBuffer(buffer, sizeof(buffer));
448
  }
449

UNCOV
450
  if (restBytes) {
×
451
    rd.ReadBuffer(buffer, restBytes);
452
    records.WriteBuffer(buffer, restBytes);
453
  }
454

455
  bool validCacheEntry = false;
456

457
  {
458
    // Find last zipfile entry and modify extraFieldSize
459
    const size_t skipValue = std::min(entriesSize, size_t(0x11000));
×
UNCOV
460
    rd.Skip(-skipValue);
×
461
    rd.ReadBuffer(buffer, skipValue);
462
    std::string_view sv(buffer, skipValue);
463
    size_t foundLastEntry = sv.rfind("PK\x01\x02");
464
    validCacheEntry = foundLastEntry != sv.npos;
465

466
    if (validCacheEntry) {
×
467
      foundLastEntry += offsetof(ZIPFile, extraFieldSize);
×
468
      char *data = buffer + foundLastEntry;
×
UNCOV
469
      uint16 extraFieldSize = *reinterpret_cast<uint16 *>(data);
×
470
      records.Push();
471
      records.Skip(-(skipValue - foundLastEntry));
×
UNCOV
472
      records.Write<uint16>(extraFieldSize + 4 + sizeof(CacheBaseHeader));
×
473
      records.Pop();
474

475
      records.Write<uint16>(0x4353);
×
476
      records.Write<uint16>(sizeof(CacheBaseHeader));
×
477
      cache.meta.zipCheckupOffset = records.Tell();
×
478
      records.Write(cache.meta);
×
UNCOV
479
      entriesSize += sizeof(CacheBaseHeader) + 4;
×
480
    }
481
  }
482

483
  SafeCast(zCentral.dirSize, entriesSize);
484

485
  if (forcex64) {
×
486
    ZIP64CentralDir zCentral64{};
×
487
    zCentral64.id = ZIP64CentralDir::ID;
×
488
    zCentral64.madeBy = 10;
×
489
    zCentral64.extractVersion = 10;
×
490
    zCentral64.numDiskEntries = numEntries;
×
491
    zCentral64.numDirEntries = numEntries;
×
492
    zCentral64.dirSize = entriesSize;
×
493
    zCentral64.dirOffset = dirOffset;
×
UNCOV
494
    zCentral64.dirRecord = 0x2C;
×
495

496
    const size_t centralOffset = records.Tell();
UNCOV
497
    records.Write(zCentral64);
×
498

499
    ZIP64CentralDirLocator zLoca{};
×
500
    zLoca.id = ZIP64CentralDirLocator::ID;
×
UNCOV
501
    zLoca.centralDirOffset = centralOffset;
×
502
    records.Write(zLoca);
503
  }
504

505
  records.Write(zCentral);
506

507
  es::Dispose(rd);
×
UNCOV
508
  es::RemoveFile(entriesFile);
×
509

510
  if (validCacheEntry) {
×
511
    cacheBeginCB();
×
512
    cache.meta.zipSize = records.Tell();
×
513
    BinWritter cacheWr(outFile + ".cache");
×
514
    cache.WaitAndWrite(cacheWr);
×
515
    records.Seek(cache.meta.zipCheckupOffset);
×
UNCOV
516
    records.Write(cache.meta);
×
517
  }
518
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc