예제 #1
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_;
  }
예제 #2
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_;
  }