Пример #1
0
  //----------------------------------------------------------------
  // IElement::loadCrc32
  //
  uint64
  IElement::loadCrc32(IStorage & storage,
                      uint64 bytesToRead)
  {
    if (!bytesToRead)
    {
      return 0;
    }

    // save current seek position, so it can be restored if necessary:
    IStorage::TSeek storageStart(storage);
    IStorage::IReceiptPtr receiptCrc32 = storage.receipt();

    uint64 eltId = loadEbmlId(storage);
    if (eltId != kIdCrc32)
    {
      return 0;
    }

    if (offsetToCrc32_ != kUndefinedOffset)
    {
      // only one CRC-32 element is allowed per master element:
      assert(false);
      return 0;
    }

    uint64 vsizeSize = 0;
    uint64 vsize = vsizeDecode(storage, vsizeSize);
    if (vsize != 4)
    {
      // wrong CRC-32 payload size:
      return 0;
    }

    // load CRC (it is stored in little endian layout)
    TEightByteBuffer crc32LittleEndian(4);

    if (!storage.load(crc32LittleEndian.v_, crc32LittleEndian.n_))
    {
      // failed to load CRC-32 checksum:
      return 0;
    }

    // convert to big-endian layout expected by uintDecode:
    TEightByteBuffer crc32BigEndian = crc32LittleEndian.reverseByteOrder();

    // update the receipt:
    receiptCrc32->add(uintNumBytes(kIdCrc32) + vsizeSize + 4);

    // successfully loaded the CRC-32 element:
    storageStart.doNotRestore();

    setCrc32(true);
    storedCrc32_ = (unsigned int)uintDecode(crc32BigEndian.v_,
                                            crc32BigEndian.n_);
    offsetToCrc32_ = receiptCrc32->position() - receipt_->position();

    uint64 bytesRead = receiptCrc32->numBytes();
    assert(bytesRead == kCrc32EltSize);

    return bytesRead;
  }
Пример #2
0
  //----------------------------------------------------------------
  // IElement::save
  //
  IStorage::IReceiptPtr
  IElement::save(IStorage & storage, uint64 vsizeBytesToUse) const
  {
    if (fixedSize_)
    {
      return savePaddedUpToSize(storage, fixedSize_);
    }

    if (!mustSave())
    {
      return storage.receipt();
    }

    unsigned char v[8];
    uint64 elementIdSize = uintNumBytes(getId());
    uintEncode(getId(), v, elementIdSize);
    receipt_ = storage.save(v, (std::size_t)elementIdSize);
    if (!receipt_)
    {
      return receipt_;
    }

    // shortcut:
    const IPayload & payload = getPayload();

    // NOTE: due to VEltPosition the payload size is not actually
    // known until the payload is written, however we know the
    // payload size upper limit.  Once the payload is saved it's
    // exact size will have to be saved again:
    uint64 payloadSize = payload.calcSize();

    // must account for CRC-32 element as well:
    if (shouldComputeCrc32())
    {
      payloadSize += uintNumBytes(kIdCrc32) + vsizeNumBytes(4) + 4;
    }

    // if necessary calculate number of bytes used to store the payload size:
    if (!vsizeBytesToUse)
    {
      vsizeBytesToUse = vsizeNumBytes(payloadSize);
    }

    vsizeEncode(payloadSize, v, vsizeBytesToUse);
    IStorage::IReceiptPtr payloadSizeReceipt =
      storage.save(v, (std::size_t)vsizeBytesToUse);
    *receipt_ += payloadSizeReceipt;

    // save payload receipt:
    offsetToPayload_ = elementIdSize + vsizeBytesToUse;
    offsetToCrc32_ = kUndefinedOffset;

    // save CRC-32 element placeholder:
    if (shouldComputeCrc32())
    {
      IStorage::IReceiptPtr receiptCrc32 = storage.receipt();
      TByteVec bytes;
      bytes << uintEncode(kIdCrc32)
            << vsizeEncode(4)
            << uintEncode(0, 4);

      receiptCrc32 = Yamka::save(storage, bytes);
      if (!receiptCrc32)
      {
        return receiptCrc32;
      }

      *receipt_ += receiptCrc32;
      offsetToCrc32_ = offsetToPayload_;
    }

    // save the payload:
    IStorage::IReceiptPtr receiptPayload = payload.save(storage);
    if (!receiptPayload)
    {
      return receiptPayload;
    }

    *receipt_ += receiptPayload;

    uint64 payloadBytesSaved = receipt_->numBytes() - offsetToPayload_;
    assert(payloadBytesSaved <= payloadSize);

    if (payloadBytesSaved < payloadSize)
    {
      // save exact payload size:
      vsizeEncode(payloadBytesSaved, v, vsizeBytesToUse);
      payloadSizeReceipt->save(v, (std::size_t)vsizeBytesToUse);
    }

    // save attached Void elements:
    typedef std::list<IPayload::TVoid>::const_iterator TVoidIter;
    for (TVoidIter i = payload.voids_.begin();
         i != payload.voids_.end(); ++i)
    {
      const IPayload::TVoid & eltVoid = *i;
      IStorage::IReceiptPtr voidReceipt = eltVoid.save(storage);
      *receipt_ += voidReceipt;
    }

    return receipt_;
  }
Пример #3
0
  //----------------------------------------------------------------
  // IElement::load
  //
  uint64
  IElement::load(IStorage & storage,
                 uint64 bytesToRead,
                 IDelegateLoad * loader)
  {
    if (!bytesToRead)
    {
      return 0;
    }

    // save a storage receipt so that element position references
    // can be resolved later:
    IStorage::IReceiptPtr storageReceipt = storage.receipt();

    // save current seek position, so it can be restored if necessary:
    IStorage::TSeek storageStart(storage);

    uint64 eltId = loadEbmlId(storage);
    if (eltId != getId())
    {
      // element id wrong for my type:
      return 0;
    }

#if 0 // !defined(NDEBUG) && (defined(DEBUG) || defined(_DEBUG))
    Indent::More indentMore(Indent::depth_);
    {
      IStorage::TSeek restore(storage);
      uint64 vsizeSize = 0;
      uint64 vsize = vsizeDecode(storage, vsizeSize);
      std::cout << indent()
                << std::setw(8) << uintEncode(getId()) << " @ "
                << std::hex
                << "0x" << storageStart.absolutePosition()
                << std::dec
                << " -- " << getName()
                << ", payload " << vsize << " bytes" << std::endl;
    }
#endif

    // this appears to be a good payload:
    storageStart.doNotRestore();

    // store the storage receipt:
    receipt_ = storageReceipt;

    // read payload size:
    uint64 vsizeSize = 0;
    uint64 payloadSize = vsizeDecode(storage, vsizeSize);
    const bool payloadSizeUnknown = (payloadSize == uintMax[8]);

    // keep track of the number of bytes read successfully:
    receipt_->add(uintNumBytes(eltId));
    receipt_->add(vsizeSize);

    // clear the payload checksum:
    setCrc32(false);
    storedCrc32_ = 0;
    computedCrc32_ = 0;

    // save the payload storage receipt so that element position references
    // can be resolved later:
    IStorage::IReceiptPtr receiptPayload = storage.receipt();
    offsetToPayload_ = receiptPayload->position() - receipt_->position();
    offsetToCrc32_ = kUndefinedOffset;

    // shortcut:
    IPayload & payload = getPayload();

    // container elements may be present in any order, therefore
    // not every load will succeed -- keep trying until all
    // load attempts fail:
    uint64 payloadBytesToRead = payloadSize;
    uint64 payloadBytesReadTotal = 0;
    while (payloadBytesToRead)
    {
      uint64 prevPayloadBytesToRead = payloadBytesToRead;

      // try to load some part of the payload:
      uint64 partialPayloadSize = 0;
      if (loader)
      {
        uint64 bytesRead = loader->load(storage,
                                        payloadBytesToRead,
                                        eltId,
                                        payload);
        if (bytesRead == uintMax[8])
        {
          // special case, indicating that the loader doesn't
          // want to read any more data:
          storageStart.doRestore();
          loader->loaded(*this);
          return 0;
        }

        partialPayloadSize += bytesRead;
        payloadBytesToRead -= bytesRead;
      }

      if (!partialPayloadSize)
      {
        uint64 bytesRead = payload.load(storage,
                                        payloadBytesToRead,
                                        loader);
        partialPayloadSize += bytesRead;
        payloadBytesToRead -= bytesRead;
      }

      // consume any void elements that may exist:
      IPayload::TVoid eltVoid;
      uint64 voidPayloadSize = eltVoid.load(storage,
                                            payloadBytesToRead,
                                            loader);
      if (voidPayloadSize)
      {
        payloadBytesToRead -= voidPayloadSize;

        // find an element to store the Void element, so that
        // the relative element order would be preserved:
        IStorage::IReceiptPtr voidReceipt = eltVoid.storageReceipt();
        FindElement crawler(voidReceipt->position() - 2);

        if (partialPayloadSize)
        {
          crawler.evalPayload(payload);
          assert(crawler.eltFound_);
        }

        if (crawler.eltFound_)
        {
          IPayload & dstPayload = crawler.eltFound_->getPayload();
          dstPayload.voids_.push_back(eltVoid);
        }
        else
        {
          payload.voids_.push_back(eltVoid);
        }
      }

      // consume the CRC-32 element if it exists:
      payloadBytesToRead -= loadCrc32(storage,
                                      payloadBytesToRead);

      uint64 payloadBytesRead = prevPayloadBytesToRead - payloadBytesToRead;
      payloadBytesReadTotal += payloadBytesRead;

      if (payloadBytesRead == 0)
      {
        break;
      }
    }

    if (payloadBytesReadTotal < payloadSize && !payloadSizeUnknown)
    {
      // skip unrecognized alien data:
      uint64 alienDataSize = payloadSize - payloadBytesReadTotal;

#if !defined(NDEBUG) && (defined(DEBUG) || defined(_DEBUG))
      std::cerr << indent() << "WARNING: " << getName()
                << " 0x" << uintEncode(getId())
                << " -- skipping " << alienDataSize
                << " bytes of unrecognized alien data @ 0x"
                << std::hex
                << storage.receipt()->position()
                << std::dec
                << std::endl;
#endif

      storage.skip(alienDataSize);
      payloadBytesReadTotal = payloadSize;
    }

    receiptPayload->add(payloadBytesReadTotal);
    *receipt_ += receiptPayload;

    // verify stored payload CRC-32 checksum:
    if (shouldComputeCrc32())
    {
      IStorage::IReceiptPtr receiptCrc32 = crc32Receipt();

      Crc32 crc32;
      receiptPayload->calcCrc32(crc32, receiptCrc32);
      computedCrc32_ = crc32.checksum();

      if (computedCrc32_ != storedCrc32_)
      {
#if 1 // !defined(NDEBUG) && (defined(DEBUG) || defined(_DEBUG))
        std::cerr << indent() << "WARNING: " << getName()
                  << " 0x" << uintEncode(getId())
                  << " -- checksum mismatch, loaded "
                  << std::hex << storedCrc32_
                  << ", computed " << computedCrc32_
                  << ", CRC-32 @ 0x" << receiptCrc32->position()
                  << ", payload @ 0x" << receiptPayload->position()
                  << ":" << receiptPayload->numBytes()
                  << std::dec
                  << std::endl;

        Crc32 doOverCrc32;
        receiptPayload->calcCrc32(doOverCrc32, receiptCrc32);
#endif
      }
    }

    if (loader && receipt_->numBytes())
    {
      // allow the delegate to perform post-processing on the loaded element:
      loader->loaded(*this);
    }

    return receipt_->numBytes();
  }
Пример #4
0
  //----------------------------------------------------------------
  // IElement::savePaddedUpToSize
  //
  IStorage::IReceiptPtr
  IElement::savePaddedUpToSize(IStorage & storage, uint64 paddedSize) const
  {
    // shortcut:
    const IPayload & payload = getPayload();

    const bool payloadSizeUnknown = (paddedSize == uintMax[8]);
    uint64 elementIdSize = uintNumBytes(getId());
    uint64 payloadSize = payload.calcSize();
    uint64 vsizeBytesToUse = vsizeNumBytes(payloadSize);

    // make sure the paddedSize is big enough to store the payload:
    uint64 elementSize = elementIdSize + vsizeBytesToUse + payloadSize;
    if (!payloadSizeUnknown &&
        elementSize != paddedSize &&
        elementSize + kMinVoidEltSize > paddedSize)
    {
      return IStorage::IReceiptPtr();
    }

    // save element id:
    unsigned char v[8];
    uintEncode(getId(), v, elementIdSize);
    receipt_ = storage.save(v, (std::size_t)elementIdSize);
    if (!receipt_)
    {
      return receipt_;
    }

    // save payload size:
    IStorage::IReceiptPtr payloadSizeReceipt;
    if (payloadSizeUnknown)
    {
      vsizeEncode(vsizeUnknown[8], v, 8);
      payloadSizeReceipt = storage.save(v, 8);
    }
    else
    {
      vsizeEncode(payloadSize, v, vsizeBytesToUse);
      payloadSizeReceipt = storage.save(v, (std::size_t)vsizeBytesToUse);
    }

    *receipt_ += payloadSizeReceipt;

    // save payload receipt:
    offsetToPayload_ = storage.receipt()->position() - receipt_->position();
    offsetToCrc32_ = kUndefinedOffset;

    // save the payload:
    IStorage::IReceiptPtr payloadReceipt = payload.save(storage);
    if (!payloadReceipt)
    {
      return payloadReceipt;
    }

    *receipt_ += payloadReceipt;

    if (payloadSizeUnknown)
    {
      // done:
      return receipt_;
    }

    uint64 payloadBytesSaved = payloadReceipt->numBytes();
    assert(payloadBytesSaved <= payloadSize);

    if (payloadBytesSaved < payloadSize)
    {
      // save exact payload size:
      vsizeEncode(payloadBytesSaved, v, vsizeBytesToUse);
      payloadSizeReceipt->save(v, (std::size_t)vsizeBytesToUse);
    }

    // add the padding:
    assert(payload.voids_.empty());

    elementSize = (elementIdSize + vsizeBytesToUse + payloadBytesSaved);
    uint64 voidSize = paddedSize - elementSize;

    if (voidSize >= kMinVoidEltSize)
    {
      IPayload::TVoid eltVoid;

      uint64 voidIdSize = uintNumBytes(eltVoid.getId());
      uint64 vsizeBytesToUse = vsizeNumBytes(voidSize - voidIdSize);

      eltVoid.payload_.set(voidSize - voidIdSize - vsizeBytesToUse);
      IStorage::IReceiptPtr receipt = eltVoid.save(storage, vsizeBytesToUse);

      if (receipt)
      {
        *receipt_ += receipt;
      }
    }

    return receipt_;
  }