//
//------------------------------------------------------------------------------
size_t ReflectedPropertyStruct::GetArraySize( const void * object ) const
{
    // sanity checks
    ASSERT( IsArray() );
    ASSERT( GetType() == PT_STRUCT );

    // get the array
    const size_t elementSize = GetPropertySize();
    const void * arrayBase = (const void *)( (size_t)object + m_Offset );
    const Array< char > * array = static_cast< const Array< char > * >( arrayBase );

    // calculate the size
    const size_t size = ( array->End() - array->Begin() ) / elementSize;
    return size;
}
//------------------------------------------------------------------------------
const Struct * ReflectedPropertyStruct::GetStructInArray( const void * object, size_t index ) const
{
    // sanity checks
    ASSERT( IsArray() );
    ASSERT( GetType() == PT_STRUCT );
    ASSERT( index < GetArraySize( object ) );

    // get the array
    const size_t elementSize = GetPropertySize();
    const void * arrayBase = (const void *)( (size_t)object + m_Offset );
    const Array< char > * array = static_cast< const Array< char > * >( arrayBase );

    // calculate the element offset
    const size_t offset = ( index * elementSize );
    return reinterpret_cast< Struct * >( array->Begin() + offset );
}
        STDMETHODIMP ArchiveExtractCallback::GetStream(UInt32 index, ISequentialOutStream** outStream, Int32 askExtractMode)
        {
            try
            {
                // Retrieve all the various properties for the file at this index.
                GetPropertyFilePath(index);
                if (askExtractMode != NArchive::NExtract::NAskMode::kExtract)
                {
                    return S_OK;
                }

                GetPropertyAttributes(index);
                GetPropertyIsDir(index);
                GetPropertyModifiedTime(index);
                GetPropertyCreatedTime(index);
                GetPropertyAccessedTime(index);
                GetPropertySize(index);
            }
            catch (_com_error& ex)
            {
                wprintf_s(L"获取数据失败\n");
                return ex.Error();
            }

            // TODO: m_directory could be a relative path as "..\"
            m_absPath = FileSys::AppendPath(m_directory, m_relPath);

            if (m_isDir)
            {
                wprintf_s(L"DirBegin:%s\n", m_absPath.c_str());
                FileSys::CreateDirectoryTree(m_absPath);
                *outStream = NULL;
                return S_OK;
            }

            if (m_callback)
            {
                if (!m_callback->OnFileBegin(m_directory, m_relPath))
                {
                    //stop decompress
                    return E_FAIL;
                }
                //Skip file
                if (m_relPath.empty())
                {
                    *outStream = NULL;
                    return S_OK;
                } 
            }

            wprintf_s(L"FileBegin:%s\n", m_absPath.c_str());
            if (m_overwriteMode == OverwriteMode::kRollBack)
            {
                TString BackupPath;
                if (FileSys::PathExists(m_absPath))
                {
                    BackupPath = FileSys::GetUniquePath(m_absPath);
                    if (!FileSys::BackupFile(m_absPath, BackupPath))
                        return HRESULT_FROM_WIN32(GetLastError());
                }
                RollBack_Info info;
                info.backup_path = BackupPath;
                info.original_path = m_absPath;
                m_rollbacks.push_back(info);
            }
            else if (FileSys::PathExists(m_absPath))
            {
                if (m_overwriteMode == OverwriteMode::kSkipExisting)
                {
                    *outStream = NULL;
                    return S_OK;
                }
                else if (m_overwriteMode == OverwriteMode::kAutoRename)
                {
                    m_absPath = FileSys::GetUniquePath(m_absPath);
                }
                else if (m_overwriteMode == OverwriteMode::kAutoRenameExisting)
                {
                    TString rename_path = FileSys::GetUniquePath(m_absPath);
                    if (!FileSys::RenameFile(m_absPath, rename_path))
                    {
                        wprintf_s(L"重命名文件失败:%s-%s\n", m_absPath.c_str(), rename_path.c_str());
                        return HRESULT_FROM_WIN32(GetLastError());
                    }
                }
                else if (m_overwriteMode == OverwriteMode::kWithoutPrompt)
                {
                    if (!FileSys::RemovePath(m_absPath))
                    {
                        wprintf_s(L"移除路径失败:%s\n", m_absPath.c_str());
                        return HRESULT_FROM_WIN32(GetLastError());
                    }
                }
                else
                {
                    wprintf_s(L"文件已存在:%s\n", m_absPath.c_str());
                    return ERROR_FILE_EXISTS;
                }
            }

            TString absDir = FileSys::GetPath(m_absPath);
            if (!FileSys::CreateDirectoryTree(absDir))
            {
                wprintf_s(L"创建目录失败:%s\n", absDir.c_str());
                return ERROR_CREATE_FAILED;
            }

            CMyComPtr< IStream > fileStream = FileSys::OpenFileToWrite(m_absPath);
            if (fileStream == NULL)
            {
                wprintf_s(L"创建文件失败:%s\n", m_absPath.c_str());
                m_absPath.clear();
                return HRESULT_FROM_WIN32(GetLastError());
            }

            OutStreamWrapper* stream = new OutStreamWrapper(fileStream);
            if (!stream)
            {
                wprintf_s(L"内存不足\n");
                return E_OUTOFMEMORY;
            }

            CMyComPtr< OutStreamWrapper > wrapperStream = stream;
            *outStream = wrapperStream.Detach();

            return S_OK;
        }