#ifndef _MSC_VER
#include "StdAfx.h" //C++Builder(プレイヤー本体用)
#pragma hdrstop
#else
#include <windows.h>
#include <stdlib.h>
#endif

#include "ringbuf.h"

///////////////////////////////////////////////////////////////////////////////
KbRingBuffer::KbRingBuffer(void)
{
    m_pBuffer = NULL;
    m_dwReadPos = 0;
    m_dwWritePos = 0;
    m_dwWritten = 0;
    m_dwBufferSize = 0;
}
///////////////////////////////////////////////////////////////////////////////
KbRingBuffer::~KbRingBuffer(void)
{
    if (m_pBuffer) {
        free(m_pBuffer);
    }
}
///////////////////////////////////////////////////////////////////////////////
DWORD __fastcall KbRingBuffer::Discard(DWORD dwSize)
{// 書き込んだバッファから dwSize だけ捨てる
 // 捨てたサイズを返す
    if (m_dwWritten < dwSize) {
        dwSize = m_dwWritten;
    }
    if (m_dwWritePos >= dwSize) {
        m_dwWritePos -= dwSize;
    }
    else {
        m_dwWritePos = m_dwBufferSize - (dwSize - m_dwWritePos);
    }
    m_dwWritten -= dwSize;
    return dwSize;
}
///////////////////////////////////////////////////////////////////////////////
void __fastcall KbRingBuffer::SetSize(DWORD dwNewSize)
{// リングバッファのサイズを拡大・縮小する
 // サイズを縮小する場合は、縮小前のデータはすべて失われる
 // サイズを拡大する場合は、拡大前後でデータは失われない
    BYTE *pNewBuf;
    if (dwNewSize < m_dwBufferSize) { // 縮小する
        m_dwReadPos = m_dwWritePos = m_dwWritten = 0; // 縮小前のデータはすべて失われる
    }
    pNewBuf = (BYTE*)realloc(m_pBuffer, dwNewSize);
    if (m_dwReadPos > m_dwWritePos ||
        (m_dwReadPos == m_dwWritePos && m_dwWritten != 0)) {
        DWORD dwExpandSize = dwNewSize - m_dwBufferSize;
        // memmove(pNewBuf + m_dwReadPos + dwExpandSize, pNewBuf+m_dwReadPos,
        // m_dwBufferSize-m_dwReadPos);
        const DWORD *end4 = (DWORD*)(pNewBuf + m_dwReadPos);
        DWORD *src4 = (DWORD*)(pNewBuf + m_dwBufferSize - 4);
        DWORD *dst4 = (DWORD*)((BYTE*)src4 + dwExpandSize);
        while (src4 >= end4) {
            *dst4-- = *src4--;
        }
        BYTE *src = (BYTE*)src4 + 3;
        BYTE *dst = (BYTE*)dst4;
        while (src >= (const BYTE*)end4) {
            *dst-- = *src--;
        }
        m_dwReadPos += dwExpandSize;
    }
    m_pBuffer = pNewBuf;
    m_dwBufferSize = dwNewSize;
}
///////////////////////////////////////////////////////////////////////////////
DWORD __fastcall KbRingBuffer::Read(BYTE* buf, DWORD dwSize)
{ // リングバッファの内容を読み取る
  // 実際に読み取ったバイト数を返す
    if (dwSize > m_dwWritten) {
        dwSize = m_dwWritten;
    }
    DWORD dwCopyFirst; // 先頭部分からのコピーサイズ
    DWORD dwCopyTail; // 終端部分からのコピーサイズ
    dwCopyTail = m_dwBufferSize - m_dwReadPos;
    if (dwCopyTail > dwSize) {
        dwCopyTail = dwSize;
    }
    dwCopyFirst = dwSize - dwCopyTail;

    if (dwCopyTail){
        memcpy(buf, m_pBuffer + m_dwReadPos, dwCopyTail);
    }
    if (dwCopyFirst){
        memcpy(buf + dwCopyTail, m_pBuffer, dwCopyFirst);
    }
    m_dwReadPos += dwSize;
    if (m_dwReadPos > m_dwBufferSize) {
        m_dwReadPos -= m_dwBufferSize;
    }
    m_dwWritten -= dwSize;
    return dwSize;
}
///////////////////////////////////////////////////////////////////////////////
DWORD __fastcall KbRingBuffer::ReadDirect(BYTE** ppBuf, DWORD dwSize)
{ // リングバッファの内容を直接読み取る
  // 実際に読み取ったバイト数を返す
  // 末尾と先頭の境界をまたがる場合は NULL を返す
    if (dwSize > m_dwWritten) {
        dwSize = m_dwWritten;
    }
    DWORD dwCopyFirst; // 先頭部分からのコピーサイズ
    DWORD dwCopyTail; // 終端部分からのコピーサイズ
    dwCopyTail = m_dwBufferSize - m_dwReadPos;
    if (dwCopyTail > dwSize) {
        dwCopyTail = dwSize;
    }
    dwCopyFirst = dwSize - dwCopyTail;
    if (dwCopyTail) {
        if (dwCopyFirst) {
            *ppBuf = NULL;
            return 0;
        }
        *ppBuf = m_pBuffer + m_dwReadPos;
    }
    else {
        *ppBuf = m_pBuffer;
    }
    m_dwReadPos += dwSize;
    if (m_dwReadPos > m_dwBufferSize) {
        m_dwReadPos -= m_dwBufferSize;
    }
    m_dwWritten -= dwSize;
    return dwSize;
}
///////////////////////////////////////////////////////////////////////////////
void __fastcall KbRingBuffer::Write(const BYTE* buf, DWORD dwSize)
{// リングバッファに書き込む
 // バッファサイズが足りない場合は拡大する
    if (!m_pBuffer || m_dwBufferSize - m_dwWritten < dwSize) {
        SetSize(m_dwWritten + dwSize);
    }
    DWORD dwCopyFirst; // 先頭部分へのコピーサイズ
    DWORD dwCopyTail; // 終端部分へのコピーサイズ
    dwCopyTail = m_dwBufferSize - m_dwWritePos;
    if (dwCopyTail > dwSize) {
        dwCopyTail = dwSize;
    }
    dwCopyFirst = dwSize - dwCopyTail;
    if (dwCopyTail){
        memcpy(m_pBuffer + m_dwWritePos, buf, dwCopyTail);
    }
    if (dwCopyFirst){
        memcpy(m_pBuffer, buf + dwCopyTail, dwCopyFirst);
    }
    m_dwWritePos += dwSize;
    if (m_dwWritePos > m_dwBufferSize) {
        m_dwWritePos -= m_dwBufferSize;
    }
    m_dwWritten += dwSize;
}
///////////////////////////////////////////////////////////////////////////////
BOOL __fastcall KbRingBuffer::LockBuffer(BYTE **ppBuf1, BYTE **ppBuf2,
                                         DWORD *pdwSize1, DWORD *pdwSize2,
                                         DWORD dwSize)
{ // リングバッファに直接書き込む
  // 戻り値への書き込みは呼び出し側で行う
  // バッファサイズが足りない場合は拡大する
    if (!m_pBuffer || m_dwBufferSize - m_dwWritten < dwSize) {
        SetSize(m_dwWritten + dwSize);
    }
    DWORD dwCopyTail; // 終端部分へのコピーサイズ
    dwCopyTail = m_dwBufferSize - m_dwWritePos;
    if (dwCopyTail > dwSize) {
        dwCopyTail = dwSize;
    }
    *ppBuf1 = m_pBuffer + m_dwWritePos;
    *pdwSize1 = dwCopyTail;
    *ppBuf2 = m_pBuffer;
    *pdwSize2 = dwSize - dwCopyTail;
    return TRUE;
}
///////////////////////////////////////////////////////////////////////////////
void __fastcall KbRingBuffer::UnlockBuffer(DWORD dwSize)
{ // リングバッファへの直接書き込み終了
    m_dwWritePos += dwSize;
    if(m_dwWritePos >= m_dwBufferSize){
        m_dwWritePos -= m_dwBufferSize;
    }
    m_dwWritten += dwSize;
}
///////////////////////////////////////////////////////////////////////////////

