BOOL SimpleStorage::Compact()
{
    GLOBAL_LOCK(irq);
    BlockStorageStream* pFreeBlock = (s_pCurrentStream == &s_BsStreamA) ? &s_BsStreamB : &s_BsStreamA;
    SIMPLESTORAGE_FILE_HEADER header;
    UINT8 buffer[256];
    const UINT32 eraseBlock = 0x0;
    const UINT32 activeBlock = SIMPLESTORAGE_ACTIVE_BLOCK_MARKER;

    pFreeBlock->Seek(0, BlockStorageStream::SeekBegin);
    if(!pFreeBlock->Erase(pFreeBlock->Length)) return FALSE;

    pFreeBlock->Seek(sizeof(SIMPLESTORAGE_BLOCK_HEADER), BlockStorageStream::SeekBegin);

    s_pCurrentStream->Seek(sizeof(SIMPLESTORAGE_BLOCK_HEADER), BlockStorageStream::SeekBegin);

    do
    {
        INT32 len;
        
        if(!ReadToNextFile(header)) break;

        if(header.Signature != SIMPLESTORAGE_FILE_SIGNATURE) break;

        pFreeBlock->Write((UINT8*)&header, sizeof(header));

        len = header.Length;
        while(len > 0)
        {
            int bufLen = len < ARRAYSIZE(buffer) ? len : ARRAYSIZE(buffer);
            
            if(!s_pCurrentStream->ReadIntoBuffer((UINT8*)buffer, bufLen)) break;
            if(!pFreeBlock->Write((UINT8*)buffer, bufLen)) break;

            len -= bufLen;
        }
    }
    while(s_pCurrentStream->CurrentIndex + sizeof(header) < s_pCurrentStream->Length);

    s_pCurrentStream->Seek(0, BlockStorageStream::SeekBegin);

    s_pCurrentStream->Write((UINT8*)&eraseBlock, sizeof(eraseBlock));

    pFreeBlock->Seek(0, BlockStorageStream::SeekBegin);

    pFreeBlock->Write((UINT8*)&activeBlock, sizeof(activeBlock)); 

    s_pCurrentStream = pFreeBlock;

    return TRUE;
}
BOOL MicroBooterUpdateProvider::InstallUpdate( MFUpdate* pUpdate, UINT8* pValidation, INT32 validationLen )
{
    if(pUpdate->Providers->Storage == NULL) return FALSE;

    if(!pUpdate->IsValidated()) return FALSE;

    switch(pUpdate->Header.UpdateType)
    {
        case MFUPDATE_UPDATETYPE_FIRMWARE:
            {
                HAL_UPDATE_CONFIG cfg;

                if(sizeof(cfg.UpdateSignature) < validationLen) return FALSE;
                
                cfg.Header.Enable = TRUE;
                cfg.UpdateID = pUpdate->Header.UpdateID;

                if(validationLen == sizeof(UINT32))
                {
                    cfg.UpdateSignType = HAL_UPDATE_CONFIG_SIGN_TYPE__CRC;
                }
                else
                {
                    cfg.UpdateSignType = HAL_UPDATE_CONFIG_SIGN_TYPE__SIGNATURE;
                }
                
                memcpy( cfg.UpdateSignature, pValidation, validationLen );

                if(HAL_CONFIG_BLOCK::UpdateBlockWithName(cfg.GetDriverName(), &cfg, sizeof(cfg), FALSE))
                {
                    CPU_Reset();
                }
            }
            break;
            
        case MFUPDATE_UPDATETYPE_ASSEMBLY:
            {
                BlockStorageStream stream;
                
                if(NULL == BlockStorageList::GetFirstDevice())
                {
                    BlockStorageList::Initialize();
                
                    BlockStorage_AddDevices();
                
                    BlockStorageList::InitializeDevices();
                }

                if(stream.Initialize(BlockUsage::DEPLOYMENT))
                {
                    if(pUpdate->Header.UpdateSubType == MFUPDATE_UPDATESUBTYPE_ASSEMBLY_REPLACE_DEPLOY)
                    {
                        do
                        {
                            stream.Erase(stream.Length);
                        }
                        while(stream.NextStream());

                        stream.Initialize(BlockUsage::DEPLOYMENT);
                    }
                    
                    do
                    {
                        UINT8 buf[512];
                        INT32 offset = 0;
                        INT32 len = sizeof(buf);
                        const BlockDeviceInfo* deviceInfo = stream.Device->GetDeviceInfo();
                        BOOL isXIP = deviceInfo->Attribute.SupportsXIP;
                        
                        const CLR_RECORD_ASSEMBLY* header;
                        INT32  headerInBytes = sizeof(CLR_RECORD_ASSEMBLY);
                        BYTE * headerBuffer  = NULL;
                        
                        if(!isXIP)
                        {
                            headerBuffer = (BYTE*)private_malloc( headerInBytes );  if(!headerBuffer) return FALSE;
                            memset( headerBuffer, 0,  headerInBytes );
                        }
                        
                        while(TRUE)
                        {
                            if(!stream.Read( &headerBuffer, headerInBytes )) break;
                        
                            header = (const CLR_RECORD_ASSEMBLY*)headerBuffer;
                        
                            // check header first before read
                            if(!header->GoodHeader())
                            {
                                stream.Seek(-headerInBytes);
                                
                                if(stream.IsErased(pUpdate->Header.UpdateSize))
                                {
                                    while(offset < pUpdate->Header.UpdateSize)
                                    {
                                        if((pUpdate->Header.UpdateSize - offset) < len)
                                        {
                                            len = pUpdate->Header.UpdateSize - offset;
                                        }
                                        
                                        offset += pUpdate->Providers->Storage->Read(pUpdate->StorageHandle, offset, buf, len);

                                        stream.Write(buf, len);
                                    }

                                    ClrReboot();
                                    return TRUE;
                                }
                                break;
                            }
                        
                            UINT32 AssemblySizeInByte = ROUNDTOMULTIPLE(header->TotalSize(), CLR_UINT32);
                        
                            stream.Seek( AssemblySizeInByte );
                        }
                        if(!isXIP) private_free( headerBuffer );
                    
                    }
                    while(stream.NextStream());
                }

            }
            break;
    }
    
    return FALSE;
}