OSDN Git Service

add tsid channel information for complete BS support.
[rec10/rec10-git.git] / b25-remote / BCasCard.cpp
index 7d8387f..893ea22 100755 (executable)
-// BcasCard.cpp: CBcasCard \83N\83\89\83X\82Ì\83C\83\93\83v\83\8a\83\81\83\93\83e\81[\83V\83\87\83\93\r
-//\r
-//////////////////////////////////////////////////////////////////////\r
-\r
-#include "W2L.h"\r
-#include "BCasCard.h"\r
-\r
-#ifdef _DEBUG\r
-#undef THIS_FILE\r
-static char THIS_FILE[]=__FILE__;\r
-#define new DEBUG_NEW\r
-#endif\r
-\r
-\r
-//#pragma comment(lib, "WinScard.lib")\r
-\r
-\r
-using std::auto_ptr;\r
-\r
-\r
-CBcasCard::CBcasCard()\r
-       : m_hBcasCard(NULL)\r
-       , m_bIsEstablish(false)\r
-       , m_dwLastError(BCEC_NOERROR)\r
-{\r
-       // \93à\95\94\8fó\91Ô\8f\89\8aú\89»\r
-       memset(&m_BcasCardInfo, 0, sizeof(m_BcasCardInfo));\r
-       memset(&m_EcmStatus,    0, sizeof(m_EcmStatus));\r
-\r
-       // \83\8a\83\\81[\83X\83}\83l\81[\83W\83\83\83R\83\93\83e\83L\83X\83g\8am\97§\r
-       if(::SCardEstablishContext(SCARD_SCOPE_USER, NULL, NULL, &m_ScardContext) != SCARD_S_SUCCESS){\r
-               m_dwLastError = BCEC_NOTESTABLISHED;\r
-               }\r
-       else{\r
-               m_bIsEstablish = true;\r
-               \r
-               // \83J\81[\83h\83\8a\81[\83_\97ñ\8b\93\r
-               EnumCardReader();\r
-               }\r
-}\r
-\r
-CBcasCard::~CBcasCard()\r
-{\r
-       CloseCard();\r
-\r
-       // \83\8a\83\\81[\83X\83}\83l\81[\83W\83\83\83R\83\93\83e\83L\83X\83g\82Ì\8aJ\95ú\r
-       if(m_bIsEstablish)::SCardReleaseContext(m_ScardContext);\r
-}\r
-\r
-const DWORD CBcasCard::GetCardReaderNum(void) const\r
-{\r
-       // \83J\81[\83h\83\8a\81[\83_\81[\90\94\82ð\95Ô\82·\r
-       return m_CardReaderArray.size();\r
-}\r
-\r
-LPCTSTR CBcasCard::GetCardReaderName(const DWORD dwIndex) const\r
-{\r
-       // \83J\81[\83h\83\8a\81[\83_\81[\96¼\82ð\95Ô\82·\r
-       return (dwIndex < GetCardReaderNum())? m_CardReaderArray[dwIndex].c_str() : NULL;\r
-}\r
-\r
-const bool CBcasCard::OpenCard(LPCTSTR lpszReader)\r
-{\r
-       // \83\8a\83\\81[\83X\83}\83l\81[\83W\83\83\83R\83\93\83e\83L\83X\83g\82Ì\8am\97§\r
-       if(!m_bIsEstablish){\r
-               m_dwLastError = BCEC_NOTESTABLISHED;\r
-               return false;\r
-               }\r
-       \r
-       // \88ê\92U\83N\83\8d\81[\83Y\82·\82é\r
-       CloseCard();\r
-\r
-\r
-       if(lpszReader){\r
-               // \8ew\92è\82³\82ê\82½\83J\81[\83h\83\8a\81[\83_\82É\91Î\82µ\82Ä\83I\81[\83v\83\93\82ð\8e\8e\82Ý\82é\r
-               DWORD dwActiveProtocol = SCARD_PROTOCOL_UNDEFINED;\r
-               \r
-               if(::SCardConnect(m_ScardContext, lpszReader, SCARD_SHARE_SHARED, SCARD_PROTOCOL_T1, &m_hBcasCard, &dwActiveProtocol) != SCARD_S_SUCCESS){\r
-                       m_dwLastError = BCEC_CARDOPENERROR;\r
-                       return false;\r
-                       }\r
-\r
-               if(dwActiveProtocol != SCARD_PROTOCOL_T1){\r
-                       CloseCard();\r
-                       m_dwLastError = BCEC_CARDOPENERROR;\r
-                       return false;\r
-                       }\r
-               }\r
-       else{\r
-               // \91S\82Ä\82Ì\83J\81[\83h\83\8a\81[\83_\82É\91Î\82µ\82Ä\83I\81[\83v\83\93\82ð\8e\8e\82Ý\82é\r
-               DWORD dwIndex = 0UL;\r
-       \r
-               while(GetCardReaderName(dwIndex)){\r
-                       if(OpenCard(GetCardReaderName(dwIndex++)))return true;                  \r
-                       }\r
-               \r
-               return false;\r
-               }\r
-\r
-       // \83J\81[\83h\8f\89\8aú\89»\r
-       if(!InitialSetting())return false;\r
-\r
-       m_dwLastError = BCEC_NOERROR;\r
-\r
-       return true;\r
-}\r
-\r
-void CBcasCard::CloseCard(void)\r
-{\r
-       // \83J\81[\83h\82ð\83N\83\8d\81[\83Y\82·\82é\r
-       if(m_hBcasCard){\r
-               ::SCardDisconnect(m_hBcasCard, SCARD_LEAVE_CARD);\r
-               m_hBcasCard = NULL;\r
-               }\r
-}\r
-\r
-const DWORD CBcasCard::GetLastError(void) const\r
-{\r
-       // \8dÅ\8cã\82É\94­\90\82µ\82½\83G\83\89\81[\82ð\95Ô\82·\r
-       return m_dwLastError;\r
-}\r
-\r
-const bool CBcasCard::EnumCardReader(void)\r
-{\r
-       // \83J\81[\83h\83\8a\81[\83_\82ð\97ñ\8b\93\82·\82é\r
-       DWORD dwBuffSize = 0UL;\r
-       \r
-       switch(::SCardListReaders(m_ScardContext, NULL, NULL, &dwBuffSize)){\r
-               case SCARD_E_NO_READERS_AVAILABLE :\r
-                       // \83J\81[\83h\83\8a\81[\83_\82ª\8c©\82Â\82©\82ç\82È\82¢\r
-                       m_dwLastError = BCEC_NOCARDREADERS;\r
-                       return false;\r
-\r
-               case SCARD_S_SUCCESS :\r
-                       // \83o\83b\83t\83@\83T\83C\83Y\8eæ\93¾\90¬\8c÷\r
-                       break;\r
-               \r
-               default:\r
-                       // \83G\83\89\81[\r
-                       m_dwLastError = BCEC_INTERNALERROR;             \r
-                       return false;\r
-               }\r
-\r
-       // \83o\83b\83t\83@\8am\95Û\r
-       auto_ptr<TCHAR> szReaders(new TCHAR[dwBuffSize]);\r
-\r
-       switch(::SCardListReaders(m_ScardContext, NULL, szReaders.get(), &dwBuffSize)){\r
-               case SCARD_E_NO_READERS_AVAILABLE :\r
-                       // \83J\81[\83h\83\8a\81[\83_\82ª\8c©\82Â\82©\82ç\82È\82¢\r
-                       m_dwLastError = BCEC_NOCARDREADERS;\r
-                       return false;\r
-\r
-               case SCARD_S_SUCCESS : {\r
-                       // \83J\81[\83h\83\8a\81[\83_\96¼\95Û\91\r
-                       LPTSTR lpszCurReader = szReaders.get();\r
-                       m_CardReaderArray.clear();\r
-                       \r
-                       while(*lpszCurReader){\r
-                               m_CardReaderArray.push_back(lpszCurReader);\r
-                               lpszCurReader += m_CardReaderArray.back().length() + 1UL;\r
-                               }\r
-                       \r
-                       break;\r
-                       }\r
-               \r
-               default:\r
-                       // \83G\83\89\81[\r
-                       m_dwLastError = BCEC_INTERNALERROR;             \r
-                       return false;\r
-               }\r
-\r
-       m_dwLastError = BCEC_NOERROR;\r
-\r
-       return true;\r
-}\r
-\r
-const bool CBcasCard::TransmitCommand(const BYTE *pSendData, const DWORD dwSendSize, BYTE *pRecvData, const DWORD dwMaxRecv, DWORD *pdwRecvSize)\r
-{\r
-       DWORD dwRecvSize = dwMaxRecv;\r
-\r
-       // \83f\81[\83^\91\97\8eó\90M\r
-       DWORD dwReturn = ::SCardTransmit(m_hBcasCard, SCARD_PCI_T1, pSendData, dwSendSize, NULL, pRecvData, &dwRecvSize);\r
-       \r
-       // \8eó\90M\83T\83C\83Y\8ai\94[\r
-       if(pdwRecvSize)*pdwRecvSize = dwRecvSize;\r
-\r
-       return (dwReturn == SCARD_S_SUCCESS)? true : false;\r
-}\r
-\r
-const bool CBcasCard::InitialSetting(void)\r
-{\r
-       static const BYTE InitSettingCmd[] = {0x90U, 0x30U, 0x00U, 0x00U, 0x00U};\r
-\r
-       // \81uInitial Setting Conditions Command\81v\82ð\8f\88\97\9d\82·\82é\r
-       if(!m_hBcasCard){\r
-               m_dwLastError = BCEC_CARDNOTOPEN;\r
-               return false;\r
-               }\r
-\r
-       // \83o\83b\83t\83@\8f\80\94õ\r
-       DWORD dwRecvSize = 0UL;\r
-       BYTE RecvData[1024];\r
-       memset(RecvData, 0, sizeof(RecvData));\r
-       \r
-       // \83R\83}\83\93\83h\91\97\90M\r
-       if(!TransmitCommand(InitSettingCmd, sizeof(InitSettingCmd), RecvData, sizeof(RecvData), &dwRecvSize)){\r
-               m_dwLastError = BCEC_TRANSMITERROR;\r
-               return false;\r
-               }\r
-\r
-       if(dwRecvSize < 57UL){\r
-               m_dwLastError = BCEC_TRANSMITERROR;\r
-               return false;           \r
-               }\r
-\r
-       // \83\8c\83X\83|\83\93\83X\89ð\90Í\r
-       memcpy(m_BcasCardInfo.BcasCardID, &RecvData[8], 6UL);           // +8   Card ID\r
-       memcpy(m_BcasCardInfo.SystemKey, &RecvData[16], 32UL);  // +16  Descrambling system key\r
-       memcpy(m_BcasCardInfo.InitialCbc, &RecvData[48], 8UL);  // +48  Descrambler CBC initial value\r
-\r
-       // ECM\83X\83e\81[\83^\83X\8f\89\8aú\89»\r
-       memset(&m_EcmStatus, 0, sizeof(m_EcmStatus));\r
-\r
-       return true;\r
-}\r
-\r
-const BYTE * CBcasCard::GetBcasCardID(void)\r
-{\r
-       // Card ID \82ð\95Ô\82·\r
-       if(!m_hBcasCard){\r
-               m_dwLastError = BCEC_CARDNOTOPEN;\r
-               return NULL;\r
-               }\r
-       \r
-       m_dwLastError = BCEC_NOERROR;\r
-       \r
-       return m_BcasCardInfo.BcasCardID;\r
-}\r
-\r
-const BYTE * CBcasCard::GetInitialCbc(void)\r
-{\r
-       // Descrambler CBC Initial Value \82ð\95Ô\82·\r
-       if(!m_hBcasCard){\r
-               m_dwLastError = BCEC_CARDNOTOPEN;\r
-               return NULL;\r
-               }\r
-       \r
-       m_dwLastError = BCEC_NOERROR;\r
-       \r
-       return m_BcasCardInfo.InitialCbc;\r
-}\r
-\r
-const BYTE * CBcasCard::GetSystemKey(void)\r
-{\r
-       // Descrambling System Key \82ð\95Ô\82·\r
-       if(!m_hBcasCard){\r
-               m_dwLastError = BCEC_CARDNOTOPEN;\r
-               return NULL;\r
-               }\r
-       \r
-       m_dwLastError = BCEC_NOERROR;\r
-       \r
-       return m_BcasCardInfo.SystemKey;\r
-}\r
-\r
-const BYTE * CBcasCard::GetKsFromEcm(const BYTE *pEcmData, const DWORD dwEcmSize)\r
-{\r
-       static const BYTE EcmReceiveCmd[] = {0x90U, 0x34U, 0x00U, 0x00U};\r
-\r
-       // \81uECM Receive Command\81v\82ð\8f\88\97\9d\82·\82é\r
-       if(!m_hBcasCard){\r
-               m_dwLastError = BCEC_CARDNOTOPEN;\r
-               return NULL;\r
-               }\r
-\r
-       // ECM\83T\83C\83Y\82ð\83`\83F\83b\83N\r
-       if(!pEcmData || (dwEcmSize < 30UL) || (dwEcmSize > 256UL)){\r
-               m_dwLastError = BCEC_BADARGUMENT;\r
-               return NULL;\r
-               }\r
-\r
-       // \83L\83\83\83b\83V\83\85\82ð\83`\83F\83b\83N\82·\82é\r
-       if(!StoreEcmData(pEcmData, dwEcmSize)){\r
-               // ECM\82ª\93¯\88ê\82Ì\8fê\8d\87\82Í\83L\83\83\83b\83V\83\85\8dÏ\82ÝKs\82ð\95Ô\82·\r
-               m_dwLastError = BCEC_NOERROR;\r
-               return m_EcmStatus.KsData;\r
-               }\r
-\r
-       // \83o\83b\83t\83@\8f\80\94õ\r
-       DWORD dwRecvSize = 0UL;\r
-       BYTE SendData[1024];\r
-       BYTE RecvData[1024];\r
-       memset(RecvData, 0, sizeof(RecvData));\r
-\r
-       // \83R\83}\83\93\83h\8d\\92z\r
-       memcpy(SendData, EcmReceiveCmd, sizeof(EcmReceiveCmd));                         // CLA, INS, P1, P2\r
-       SendData[sizeof(EcmReceiveCmd)] = (BYTE)dwEcmSize;                                                      // COMMAND DATA LENGTH\r
-       memcpy(&SendData[sizeof(EcmReceiveCmd) + 1], pEcmData, dwEcmSize);      // ECM\r
-       SendData[sizeof(EcmReceiveCmd) + dwEcmSize + 1] = 0x00U;                                        // RESPONSE DATA LENGTH\r
-\r
-       // \83R\83}\83\93\83h\91\97\90M\r
-       if(!TransmitCommand(SendData, sizeof(EcmReceiveCmd) + dwEcmSize + 2UL, RecvData, sizeof(RecvData), &dwRecvSize)){\r
-               memset(&m_EcmStatus, 0, sizeof(m_EcmStatus));\r
-               m_dwLastError = BCEC_TRANSMITERROR;\r
-               return NULL;\r
-               }\r
-\r
-       // \83T\83C\83Y\83`\83F\83b\83N\r
-       if(dwRecvSize != 25UL){\r
-               memset(&m_EcmStatus, 0, sizeof(m_EcmStatus));\r
-               m_dwLastError = BCEC_TRANSMITERROR;\r
-               return NULL;\r
-               }       \r
-       \r
-       // \83\8c\83X\83|\83\93\83X\89ð\90Í\r
-       memcpy(m_EcmStatus.KsData, &RecvData[6], sizeof(m_EcmStatus.KsData));\r
-\r
-       // \83\8a\83^\81[\83\93\83R\81[\83h\89ð\90Í\r
-       switch(((WORD)RecvData[4] << 8) | (WORD)RecvData[5]){\r
-               // Purchased: Viewing\r
-               case 0x0200U :  // Payment-deferred PPV\r
-               case 0x0400U :  // Prepaid PPV\r
-               case 0x0800U :  // Tier\r
-                       m_dwLastError = BCEC_NOERROR;\r
-                       return m_EcmStatus.KsData;\r
-               \r
-               // \8fã\8bL\88È\8aO(\8e\8b\92®\95s\89Â)\r
-               default :\r
-                       m_dwLastError = BCEC_ECMREFUSED;\r
-                       return NULL;\r
-               }\r
-}\r
-\r
-const bool CBcasCard::StoreEcmData(const BYTE *pEcmData, const DWORD dwEcmSize)\r
-{\r
-       bool bUpdate = false;\r
-       \r
-       // ECM\83f\81[\83^\94ä\8ar\r
-       if(m_EcmStatus.dwLastEcmSize != dwEcmSize){\r
-               // \83T\83C\83Y\82ª\95Ï\89»\82µ\82½\r
-               bUpdate = true;\r
-               }\r
-       else{\r
-               // \83T\83C\83Y\82ª\93¯\82\8fê\8d\87\82Í\83f\81[\83^\82ð\83`\83F\83b\83N\82·\82é\r
-               for(DWORD dwPos = 0UL ; dwPos < dwEcmSize ; dwPos++){\r
-                       if(pEcmData[dwPos] != m_EcmStatus.LastEcmData[dwPos]){\r
-                               // \83f\81[\83^\82ª\95s\88ê\92v\r
-                               bUpdate = true;\r
-                               break;\r
-                               }                       \r
-                       }\r
-               }\r
-\r
-       // ECM\83f\81[\83^\82ð\95Û\91\82·\82é\r
-       if(bUpdate){\r
-               m_EcmStatus.dwLastEcmSize = dwEcmSize;\r
-               memcpy(m_EcmStatus.LastEcmData, pEcmData, dwEcmSize);\r
-               }\r
-\r
-       return bUpdate;\r
-}\r
+// BcasCard.cpp: CBcasCard クラスのインプリメンテーション
+//
+//////////////////////////////////////////////////////////////////////
+
+#include "W2L.h"
+#include "BCasCard.h"
+
+#ifdef _DEBUG
+#undef THIS_FILE
+static char THIS_FILE[]=__FILE__;
+#define new DEBUG_NEW
+#endif
+
+
+//#pragma comment(lib, "WinScard.lib")
+
+
+using std::auto_ptr;
+
+
+CBcasCard::CBcasCard()
+       : m_hBcasCard(NULL)
+       , m_bIsEstablish(false)
+       , m_dwLastError(BCEC_NOERROR)
+{
+       // 内部状態初期化
+       memset(&m_BcasCardInfo, 0, sizeof(m_BcasCardInfo));
+       memset(&m_EcmStatus,    0, sizeof(m_EcmStatus));
+
+       // リソースマネージャコンテキスト確立
+       if(::SCardEstablishContext(SCARD_SCOPE_USER, NULL, NULL, &m_ScardContext) != SCARD_S_SUCCESS){
+               m_dwLastError = BCEC_NOTESTABLISHED;
+               }
+       else{
+               m_bIsEstablish = true;
+               
+               // カードリーダ列挙
+               EnumCardReader();
+               }
+}
+
+CBcasCard::~CBcasCard()
+{
+       CloseCard();
+
+       // リソースマネージャコンテキストの開放
+       if(m_bIsEstablish)::SCardReleaseContext(m_ScardContext);
+}
+
+const DWORD CBcasCard::GetCardReaderNum(void) const
+{
+       // カードリーダー数を返す
+       return m_CardReaderArray.size();
+}
+
+LPCTSTR CBcasCard::GetCardReaderName(const DWORD dwIndex) const
+{
+       // カードリーダー名を返す
+       return (dwIndex < GetCardReaderNum())? m_CardReaderArray[dwIndex].c_str() : NULL;
+}
+
+const bool CBcasCard::OpenCard(LPCTSTR lpszReader)
+{
+       // リソースマネージャコンテキストの確立
+       if(!m_bIsEstablish){
+               m_dwLastError = BCEC_NOTESTABLISHED;
+               return false;
+               }
+       
+       // 一旦クローズする
+       CloseCard();
+
+
+       if(lpszReader){
+               // 指定されたカードリーダに対してオープンを試みる
+               DWORD dwActiveProtocol = SCARD_PROTOCOL_UNDEFINED;
+               
+               if(::SCardConnect(m_ScardContext, lpszReader, SCARD_SHARE_SHARED, SCARD_PROTOCOL_T1, &m_hBcasCard, &dwActiveProtocol) != SCARD_S_SUCCESS){
+                       m_dwLastError = BCEC_CARDOPENERROR;
+                       return false;
+                       }
+
+               if(dwActiveProtocol != SCARD_PROTOCOL_T1){
+                       CloseCard();
+                       m_dwLastError = BCEC_CARDOPENERROR;
+                       return false;
+                       }
+               }
+       else{
+               // 全てのカードリーダに対してオープンを試みる
+               DWORD dwIndex = 0UL;
+       
+               while(GetCardReaderName(dwIndex)){
+                       if(OpenCard(GetCardReaderName(dwIndex++)))return true;                  
+                       }
+               
+               return false;
+               }
+
+       // カード初期化
+       if(!InitialSetting())return false;
+
+       m_dwLastError = BCEC_NOERROR;
+
+       return true;
+}
+
+void CBcasCard::CloseCard(void)
+{
+       // カードをクローズする
+       if(m_hBcasCard){
+               ::SCardDisconnect(m_hBcasCard, SCARD_LEAVE_CARD);
+               m_hBcasCard = NULL;
+               }
+}
+
+const DWORD CBcasCard::GetLastError(void) const
+{
+       // 最後に発生したエラーを返す
+       return m_dwLastError;
+}
+
+const bool CBcasCard::EnumCardReader(void)
+{
+       // カードリーダを列挙する
+       DWORD dwBuffSize = 0UL;
+       
+       switch(::SCardListReaders(m_ScardContext, NULL, NULL, &dwBuffSize)){
+               case SCARD_E_NO_READERS_AVAILABLE :
+                       // カードリーダが見つからない
+                       m_dwLastError = BCEC_NOCARDREADERS;
+                       return false;
+
+               case SCARD_S_SUCCESS :
+                       // バッファサイズ取得成功
+                       break;
+               
+               default:
+                       // エラー
+                       m_dwLastError = BCEC_INTERNALERROR;             
+                       return false;
+               }
+
+       // バッファ確保
+       // auto_ptr<TCHAR> cannot be used for array
+       // auto_ptr<TCHAR> szReaders(new TCHAR[dwBuffSize]);
+       std::string szReaders;
+       szReaders.resize(dwBuffSize);
+
+       switch(::SCardListReaders(m_ScardContext, NULL, (char*)szReaders.data(), &dwBuffSize)){
+               case SCARD_E_NO_READERS_AVAILABLE :
+                       // カードリーダが見つからない
+                       m_dwLastError = BCEC_NOCARDREADERS;
+                       return false;
+
+               case SCARD_S_SUCCESS : {
+                       // カードリーダ名保存
+                       LPCTSTR lpszCurReader = szReaders.data();
+                       m_CardReaderArray.clear();
+                       
+                       while(*lpszCurReader){
+                               m_CardReaderArray.push_back(lpszCurReader);
+                               lpszCurReader += m_CardReaderArray.back().length() + 1UL;
+                               }
+                       
+                       break;
+                       }
+               
+               default:
+                       // エラー
+                       m_dwLastError = BCEC_INTERNALERROR;             
+                       return false;
+               }
+
+       m_dwLastError = BCEC_NOERROR;
+
+       return true;
+}
+
+const bool CBcasCard::TransmitCommand(const BYTE *pSendData, const DWORD dwSendSize, BYTE *pRecvData, const DWORD dwMaxRecv, DWORD *pdwRecvSize)
+{
+       DWORD dwRecvSize = dwMaxRecv;
+
+       // データ送受信
+       DWORD dwReturn = ::SCardTransmit(m_hBcasCard, SCARD_PCI_T1, pSendData, dwSendSize, NULL, pRecvData, &dwRecvSize);
+       
+       // 受信サイズ格納
+       if(pdwRecvSize)*pdwRecvSize = dwRecvSize;
+
+       return (dwReturn == SCARD_S_SUCCESS)? true : false;
+}
+
+const bool CBcasCard::InitialSetting(void)
+{
+       static const BYTE InitSettingCmd[] = {0x90U, 0x30U, 0x00U, 0x00U, 0x00U};
+
+       // 「Initial Setting Conditions Command」を処理する
+       if(!m_hBcasCard){
+               m_dwLastError = BCEC_CARDNOTOPEN;
+               return false;
+               }
+
+       // バッファ準備
+       DWORD dwRecvSize = 0UL;
+       BYTE RecvData[1024];
+       memset(RecvData, 0, sizeof(RecvData));
+       
+       // コマンド送信
+       if(!TransmitCommand(InitSettingCmd, sizeof(InitSettingCmd), RecvData, sizeof(RecvData), &dwRecvSize)){
+               m_dwLastError = BCEC_TRANSMITERROR;
+               return false;
+               }
+
+       if(dwRecvSize < 57UL){
+               m_dwLastError = BCEC_TRANSMITERROR;
+               return false;           
+               }
+
+       // レスポンス解析
+       memcpy(m_BcasCardInfo.BcasCardID, &RecvData[8], 6UL);           // +8   Card ID
+       memcpy(m_BcasCardInfo.SystemKey, &RecvData[16], 32UL);  // +16  Descrambling system key
+       memcpy(m_BcasCardInfo.InitialCbc, &RecvData[48], 8UL);  // +48  Descrambler CBC initial value
+
+       // ECMステータス初期化
+       memset(&m_EcmStatus, 0, sizeof(m_EcmStatus));
+
+       return true;
+}
+
+const BYTE * CBcasCard::GetBcasCardID(void)
+{
+       // Card ID を返す
+       if(!m_hBcasCard){
+               m_dwLastError = BCEC_CARDNOTOPEN;
+               return NULL;
+               }
+       
+       m_dwLastError = BCEC_NOERROR;
+       
+       return m_BcasCardInfo.BcasCardID;
+}
+
+const BYTE * CBcasCard::GetInitialCbc(void)
+{
+       // Descrambler CBC Initial Value を返す
+       if(!m_hBcasCard){
+               m_dwLastError = BCEC_CARDNOTOPEN;
+               return NULL;
+               }
+       
+       m_dwLastError = BCEC_NOERROR;
+       
+       return m_BcasCardInfo.InitialCbc;
+}
+
+const BYTE * CBcasCard::GetSystemKey(void)
+{
+       // Descrambling System Key を返す
+       if(!m_hBcasCard){
+               m_dwLastError = BCEC_CARDNOTOPEN;
+               return NULL;
+               }
+       
+       m_dwLastError = BCEC_NOERROR;
+       
+       return m_BcasCardInfo.SystemKey;
+}
+
+const BYTE * CBcasCard::GetKsFromEcm(const BYTE *pEcmData, const DWORD dwEcmSize)
+{
+       static const BYTE EcmReceiveCmd[] = {0x90U, 0x34U, 0x00U, 0x00U};
+
+       // 「ECM Receive Command」を処理する
+       if(!m_hBcasCard){
+               m_dwLastError = BCEC_CARDNOTOPEN;
+               return NULL;
+               }
+
+       // ECMサイズをチェック
+       if(!pEcmData || (dwEcmSize < 30UL) || (dwEcmSize > 256UL)){
+               m_dwLastError = BCEC_BADARGUMENT;
+               return NULL;
+               }
+
+       // キャッシュをチェックする
+       if(!StoreEcmData(pEcmData, dwEcmSize)){
+               // ECMが同一の場合はキャッシュ済みKsを返す
+               m_dwLastError = BCEC_NOERROR;
+               return m_EcmStatus.KsData;
+               }
+
+       // バッファ準備
+       DWORD dwRecvSize = 0UL;
+       BYTE SendData[1024];
+       BYTE RecvData[1024];
+       memset(RecvData, 0, sizeof(RecvData));
+
+       // コマンド構築
+       memcpy(SendData, EcmReceiveCmd, sizeof(EcmReceiveCmd));                         // CLA, INS, P1, P2
+       SendData[sizeof(EcmReceiveCmd)] = (BYTE)dwEcmSize;                                                      // COMMAND DATA LENGTH
+       memcpy(&SendData[sizeof(EcmReceiveCmd) + 1], pEcmData, dwEcmSize);      // ECM
+       SendData[sizeof(EcmReceiveCmd) + dwEcmSize + 1] = 0x00U;                                        // RESPONSE DATA LENGTH
+
+       // コマンド送信
+       if(!TransmitCommand(SendData, sizeof(EcmReceiveCmd) + dwEcmSize + 2UL, RecvData, sizeof(RecvData), &dwRecvSize)){
+               memset(&m_EcmStatus, 0, sizeof(m_EcmStatus));
+               m_dwLastError = BCEC_TRANSMITERROR;
+               return NULL;
+               }
+
+       // サイズチェック
+       if(dwRecvSize != 25UL){
+               memset(&m_EcmStatus, 0, sizeof(m_EcmStatus));
+               m_dwLastError = BCEC_TRANSMITERROR;
+               return NULL;
+               }       
+       
+       // レスポンス解析
+       memcpy(m_EcmStatus.KsData, &RecvData[6], sizeof(m_EcmStatus.KsData));
+
+       // リターンコード解析
+       switch(((WORD)RecvData[4] << 8) | (WORD)RecvData[5]){
+               // Purchased: Viewing
+               case 0x0200U :  // Payment-deferred PPV
+               case 0x0400U :  // Prepaid PPV
+               case 0x0800U :  // Tier
+                       m_dwLastError = BCEC_NOERROR;
+                       return m_EcmStatus.KsData;
+               
+               // 上記以外(視聴不可)
+               default :
+                       m_dwLastError = BCEC_ECMREFUSED;
+                       return NULL;
+               }
+}
+
+const bool CBcasCard::StoreEcmData(const BYTE *pEcmData, const DWORD dwEcmSize)
+{
+       bool bUpdate = false;
+       
+       // ECMデータ比較
+       if(m_EcmStatus.dwLastEcmSize != dwEcmSize){
+               // サイズが変化した
+               bUpdate = true;
+               }
+       else{
+               // サイズが同じ場合はデータをチェックする
+               for(DWORD dwPos = 0UL ; dwPos < dwEcmSize ; dwPos++){
+                       if(pEcmData[dwPos] != m_EcmStatus.LastEcmData[dwPos]){
+                               // データが不一致
+                               bUpdate = true;
+                               break;
+                               }                       
+                       }
+               }
+
+       // ECMデータを保存する
+       if(bUpdate){
+               m_EcmStatus.dwLastEcmSize = dwEcmSize;
+               memcpy(m_EcmStatus.LastEcmData, pEcmData, dwEcmSize);
+               }
+
+       return bUpdate;
+}