| 452 | } |
| 453 | |
| 454 | bool CDataFileReader::Open(const char *pFullName, IStorage *pStorage, const char *pPath, int StorageType) |
| 455 | { |
| 456 | dbg_assert(m_pDataFile == nullptr, "File already open"); |
| 457 | |
| 458 | log_trace("datafile", "loading '%s' from '%s'", pFullName, pPath); |
| 459 | |
| 460 | IOHANDLE File = pStorage->OpenFile(pPath, IOFLAG_READ, StorageType); |
| 461 | if(!File) |
| 462 | { |
| 463 | log_error("datafile", "failed to open file '%s' for reading", pPath); |
| 464 | return false; |
| 465 | } |
| 466 | |
| 467 | // determine size and hashes of the file and store them |
| 468 | int64_t FileSize = 0; |
| 469 | unsigned Crc = 0; |
| 470 | SHA256_DIGEST Sha256; |
| 471 | { |
| 472 | SHA256_CTX Sha256Ctxt; |
| 473 | sha256_init(&Sha256Ctxt); |
| 474 | unsigned char aBuffer[64 * 1024]; |
| 475 | while(true) |
| 476 | { |
| 477 | const unsigned Bytes = io_read(File, aBuffer, sizeof(aBuffer)); |
| 478 | if(Bytes == 0) |
| 479 | break; |
| 480 | FileSize += Bytes; |
| 481 | Crc = crc32(Crc, aBuffer, Bytes); |
| 482 | sha256_update(&Sha256Ctxt, aBuffer, Bytes); |
| 483 | } |
| 484 | Sha256 = sha256_finish(&Sha256Ctxt); |
| 485 | if(io_seek(File, 0, IOSEEK_START) != 0) |
| 486 | { |
| 487 | io_close(File); |
| 488 | log_error("datafile", "could not seek to start after calculating hashes"); |
| 489 | return false; |
| 490 | } |
| 491 | } |
| 492 | |
| 493 | // read header |
| 494 | CDatafileHeader Header; |
| 495 | if(io_read(File, &Header, sizeof(Header)) != sizeof(Header)) |
| 496 | { |
| 497 | io_close(File); |
| 498 | log_error("datafile", "could not read file header. file truncated or not a datafile."); |
| 499 | return false; |
| 500 | } |
| 501 | |
| 502 | // check header magic |
| 503 | if((Header.m_aId[0] != 'A' || Header.m_aId[1] != 'T' || Header.m_aId[2] != 'A' || Header.m_aId[3] != 'D') && |
| 504 | (Header.m_aId[0] != 'D' || Header.m_aId[1] != 'A' || Header.m_aId[2] != 'T' || Header.m_aId[3] != 'A')) |
| 505 | { |
| 506 | io_close(File); |
| 507 | log_error("datafile", "wrong header magic. magic=%x%x%x%x", Header.m_aId[0], Header.m_aId[1], Header.m_aId[2], Header.m_aId[3]); |
| 508 | return false; |
| 509 | } |
| 510 | |
| 511 | SwapEndianInPlace(&Header); |
no test coverage detected