void CTextOutputStream::WriteString( const wchar_t* szData, //!< 書き込む文字列 int nLen //!< 書き込む文字列長。-1を渡すと自動計算。 ) { //$$メモ: 文字変換時にいちいちコピーを作ってるので効率が悪い。後々効率改善予定。 int nDataLen = nLen; if(nDataLen<0)nDataLen = wcslen(szData); const wchar_t* pData = szData; const wchar_t* pEnd = szData + nDataLen; //1行毎にカキコ。"\n"は"\r\n"に変換しながら出力。ただし、"\r\n"は"\r\r\n"に変換しない。 const wchar_t* p = pData; for (;;) { //\nを検出。ただし\r\nは除外。 const wchar_t* q = p; while(q<pEnd){ if(*q==L'\n' && !((q-1)>=p && *(q-1)==L'\r') )break; q++; } const wchar_t* lf; if(q<pEnd)lf = q; else lf = NULL; if(lf){ //\nの前まで(p~lf)出力 CNativeW cSrc(p,lf-p); CMemory cDst; m_pcCodeBase->UnicodeToCode(cSrc,&cDst); //コード変換 fwrite(cDst.GetRawPtr(),1,cDst.GetRawLength(),GetFp()); //\r\nを出力 cSrc.SetString(L"\r\n"); m_pcCodeBase->UnicodeToCode(cSrc,&cDst); fwrite(cDst.GetRawPtr(),1,cDst.GetRawLength(),GetFp()); //次へ p=lf+1; } else{ //残りぜんぶ出力 CNativeW cSrc(p,pEnd-p); CMemory cDst; m_pcCodeBase->UnicodeToCode(cSrc,&cDst); //コード変換 fwrite(cDst.GetRawPtr(),1,cDst.GetRawLength(),GetFp()); break; } } }
CTextOutputStream::CTextOutputStream(const TCHAR* tszPath, ECodeType eCodeType, bool bExceptionMode, bool bBom) : COutputStream(tszPath,_T("wb"),bExceptionMode) { m_pcCodeBase = CCodeFactory::CreateCodeBase(eCodeType,0); if(Good() && bBom){ //BOM付加 CMemory cmemBom; m_pcCodeBase->GetBom(&cmemBom); if(cmemBom.GetRawLength()>0){ fwrite(cmemBom.GetRawPtr(),cmemBom.GetRawLength(),1,GetFp()); } } }
//! UTF-8→Unicodeコード変換 // 2007.08.13 kobake 作成 EConvertResult CUtf8::_UTF8ToUnicode( const CMemory& cSrc, CNativeW* pDstMem, bool bCESU8Mode/*, bool decodeMime*/ ) { // エラー状態 bool bError = false; // データ取得 int nSrcLen; const char* pSrc = reinterpret_cast<const char*>( cSrc.GetRawPtr(&nSrcLen) ); const char* psrc = pSrc; int nsrclen = nSrcLen; // CMemory cmem; // // MIME ヘッダーデコード // if( decodeMime == true ){ // bool bret = MIMEHeaderDecode( pSrc, nSrcLen, &cmem, CODE_UTF8 ); // if( bret == true ){ // psrc = reinterpret_cast<char*>( cmem.GetRawPtr() ); // nsrclen = cmem.GetRawLength(); // } // } // 必要なバッファサイズを調べて確保する wchar_t* pDst; try{ pDst = new wchar_t[nsrclen]; }catch( ... ){ pDst = NULL; } if( pDst == NULL ){ return RESULT_FAILURE; } // 変換 int nDstLen = Utf8ToUni( psrc, nsrclen, pDst, bCESU8Mode ); // pDstMem を更新 pDstMem->_GetMemory()->SetRawDataHoldBuffer( pDst, nDstLen*sizeof(wchar_t) ); // 後始末 delete [] pDst; if( bError == false ){ return RESULT_COMPLETE; }else{ return RESULT_LOSESOME; } }
/* uudecodeして保存 */ void CViewCommander::Command_UUDECODE( void ) { /* テキストが選択されているか */ if( !m_pCommanderView->GetSelectionInfo().IsTextSelected() ){ ErrorBeep(); return; } // 選択範囲のデータを取得 -> cmemBuf // 正常時はTRUE,範囲未選択の場合はFALSEを返す CNativeW ctextBuf; if( !m_pCommanderView->GetSelectedDataSimple(ctextBuf) ){ ErrorBeep(); return; } // uudecode(デコード) ctextBuf -> cmemBin, szPath CMemory cmemBin; TCHAR szPath[_MAX_PATH]=_T(""); CDecode_UuDecode decoder; if( !decoder.CallDecode(ctextBuf, &cmemBin) ){ return; } decoder.CopyFilename( szPath ); ctextBuf.Clear(); /* 保存ダイアログ モーダルダイアログの表示 */ if( !GetDocument()->m_cDocFileOperation.SaveFileDialog( szPath ) ){ return; } //データ int nDataLen; const void* pData = cmemBin.GetRawPtr(&nDataLen); //カキコ CBinaryOutputStream out(szPath); if( !out )goto err; if( nDataLen != out.Write(pData,nDataLen) )goto err; //完了 return; err: ErrorBeep(); ErrorMessage( m_pCommanderView->GetHwnd(), LS(STR_ERR_CEDITVIEW_CMD16), szPath ); }
/* Base64デコードして保存 */ void CViewCommander::Command_BASE64DECODE( void ) { /* テキストが選択されているか */ if( !m_pCommanderView->GetSelectionInfo().IsTextSelected() ){ ErrorBeep(); return; } /* 選択範囲のデータを取得 */ /* 正常時はTRUE,範囲未選択の場合はFALSEを返す */ CNativeW ctextBuf; if( !m_pCommanderView->GetSelectedDataSimple(ctextBuf) ){ ErrorBeep(); return; } /* Base64デコード */ CMemory cmemBuf; bool bret = CDecode_Base64Decode().CallDecode(ctextBuf, &cmemBuf); if( !bret ){ return; } ctextBuf.Clear(); /* 保存ダイアログ モーダルダイアログの表示 */ TCHAR szPath[_MAX_PATH] = _T(""); if( !GetDocument()->m_cDocFileOperation.SaveFileDialog( szPath ) ){ return; } //データ int nDataLen; const void* pData = cmemBuf.GetRawPtr(&nDataLen); //カキコ CBinaryOutputStream out(szPath); if(!out)goto err; if( nDataLen != out.Write(pData, nDataLen) )goto err; return; err: ErrorBeep(); ErrorMessage( m_pCommanderView->GetHwnd(), LS(STR_ERR_CEDITVIEW_CMD14), szPath ); }
//2007.08.13 kobake 追加 EConvertResult CEuc::EUCToUnicode(const CMemory& cSrc, CNativeW* pDstMem) { // エラー状態 bool bError = false; // ソース取得 int nSrcLen; const char* pSrc = reinterpret_cast<const char*>( cSrc.GetRawPtr(&nSrcLen) ); // 変換先バッファサイズとその確保 wchar_t* pDst; try{ pDst = new wchar_t[nSrcLen]; }catch( ... ){ pDst = NULL; } if( pDst == NULL ){ return RESULT_FAILURE; } // 変換 int nDstLen = EucjpToUni( pSrc, nSrcLen, pDst, &bError ); // pDstMem を更新 pDstMem->_GetMemory()->SetRawDataHoldBuffer( pDst, nDstLen*sizeof(wchar_t) ); // 後始末 delete [] pDst; //$$ SJISを介しているので無駄にデータを失うかも? // エラーを返すようにする。 2008/5/12 Uchi if( bError == false ){ return RESULT_COMPLETE; }else{ return RESULT_LOSESOME; } }
/*! UTF-7 セットBの文字列か @return セットB文字列の長さ @param[out] ppNextChar 次のブロック(UTF-7セットD部分)の先頭文字のポインタが格納される(文字'-'を飛ばす) @note この関数の前に CheckUtf7DPart() が実行される必要がある。 */ int CheckUtf7BPart( const char *pS, const int nLen, char **ppNextChar, bool *pbError, const int nOption ) { const char *pr, *pr_end; bool berror_found, bminus_found; int nchecklen; wchar_t* pdata; int ndatalen, nret; ECharSet echarset; CMemory cmbuffer; if( nLen < 1 ){ if( pbError ){ *pbError = false; } *ppNextChar = const_cast<char*>( pS ); return 0; } berror_found = false; bminus_found = false; pr = pS; pr_end = pS + nLen; for( ; pr < pr_end; ++pr ){ // セットBの文字でなくなるまでループ if( !IsBase64(*pr) ){ if( *pr == '-' ){ bminus_found= true; }else{ bminus_found = false; } break; } } nchecklen = pr - pS; // 保護コード if( nchecklen < 1 ){ nchecklen = 0; } /* ◆ デコード後のデータ長の確認 調査してきたデータ長 nchecklen(= pr - pS) を8で割ってみる. その余りの値から考えられるビット列は… |----------------------------- Base64 表現 --------------------------------------------| 第1バイト 第2バイト 第3バイト 第4バイト 第5バイト 第6バイト 第7バイト 第8バイト 残り1文字 00xx xxxx 00xx xxxx 00xx xx00 --- --- --- --- --- 残り2文字 00xx xxxx 00xx xxxx 00xx xxxx 00xx xxxx 00xx xxxx 00xx 0000 --- --- 残り3文字 00xx xxxx 00xx xxxx 00xx xxxx 00xx xxxx 00xx xxxx 00xx xxxx 00xx xxxx 00xx xxxx 上記3通りのいづれにも当てはまらない場合は全データを落とす(不正バイトとする). */ const char *pr_ = pr - 1; switch( nchecklen % 8 ){ case 0: break; case 3: if( Base64ToVal(pr_[0]) & 0x03 ){ berror_found = true; } break; case 6: if( Base64ToVal(pr_[0]) & 0x0f ){ berror_found = true; } break; case 8: // nchecklen == 0 の場合 break; default: berror_found = true; } if( UC_LOOSE == (nOption & UC_LOOSE) ){ goto EndFunc; } // UTF-7文字列 "+-" のチェック if( pr < pr_end && (nchecklen < 1 && bminus_found != true) ){ // 読み取りポインタがデータの終端を指していなくて // 確認できた Set B 文字列の長さがゼロの場合は、 // 必ず終端文字 '-' が存在していることを確認する。 berror_found = true; } // 実際にデコードして内容を確認する。 if( berror_found == true || nchecklen < 1 ){ goto EndFunc; } cmbuffer.AllocBuffer( nchecklen ); pdata = reinterpret_cast<wchar_t*>( cmbuffer.GetRawPtr() ); if( pdata == NULL ){ goto EndFunc; } ndatalen = _DecodeBase64(pS, nchecklen, reinterpret_cast<char*>(pdata)) / sizeof(wchar_t); CMemory::SwapHLByte( reinterpret_cast<char*>(pdata), ndatalen*sizeof(wchar_t) ); for( int i = 0; i < ndatalen; i += nret ){ nret = CheckUtf16leChar( &pdata[i], ndatalen - i, &echarset, nOption & UC_NONCHARACTER ); if( echarset == CHARSET_BINARY ){ berror_found = true; goto EndFunc; } if( nret == 1 && IsUtf7SetD(pdata[i]) ){ berror_found = true; goto EndFunc; } } EndFunc:; if( pbError ){ *pbError = berror_found; } if( (berror_found == false || UC_LOOSE == (nOption & UC_LOOSE)) && (pr < pr_end && bminus_found == true) ){ // '-' をスキップ。 *ppNextChar = const_cast<char*>(pr) + 1; }else{ *ppNextChar = const_cast<char*>(pr); } return nchecklen; }
/*! バッファ内容をファイルに書き出す (テスト用) @note Windows用にコーディングしてある @date 2003.07.26 ryoji BOM引数追加 */ EConvertResult CWriteManager::WriteFile_From_CDocLineMgr( const CDocLineMgr& pcDocLineMgr, //!< [in] const SSaveInfo& sSaveInfo //!< [in] ) { EConvertResult nRetVal = RESULT_COMPLETE; std::auto_ptr<CCodeBase> pcCodeBase( CCodeFactory::CreateCodeBase(sSaveInfo.eCharCode,0) ); { // 変換テスト CNativeW buffer = L"abcde"; CMemory tmp; EConvertResult e = pcCodeBase->UnicodeToCode( buffer, &tmp ); if(e==RESULT_FAILURE){ nRetVal=RESULT_FAILURE; ErrorMessage( CEditWnd::getInstance()->GetHwnd(), LS(STR_FILESAVE_CONVERT_ERROR), sSaveInfo.cFilePath.c_str() ); return nRetVal; } } try { //ファイルオープン CBinaryOutputStream out(sSaveInfo.cFilePath,true); //各行出力 int nLineNumber = 0; const CDocLine* pcDocLine = pcDocLineMgr.GetDocLineTop(); // 1行目 { ++nLineNumber; CMemory cmemOutputBuffer; { CNativeW cstrSrc; CMemory cstrBomCheck; pcCodeBase->GetBom( &cstrBomCheck ); if( sSaveInfo.bBomExist && 0 < cstrBomCheck.GetRawLength() ){ // 1行目にはBOMを付加する。エンコーダでbomがある場合のみ付加する。 CUnicode().GetBom( cstrSrc._GetMemory() ); } if( pcDocLine ){ cstrSrc.AppendNativeData( pcDocLine->_GetDocLineDataWithEOL() ); } EConvertResult e = pcCodeBase->UnicodeToCode( cstrSrc, &cmemOutputBuffer ); if(e==RESULT_LOSESOME){ nRetVal=RESULT_LOSESOME; } if(e==RESULT_FAILURE){ nRetVal=RESULT_FAILURE; ErrorMessage( CEditWnd::getInstance()->GetHwnd(), LS(STR_FILESAVE_CONVERT_ERROR), sSaveInfo.cFilePath.c_str() ); throw CError_FileWrite(); } } out.Write(cmemOutputBuffer.GetRawPtr(), cmemOutputBuffer.GetRawLength()); if( pcDocLine ){ pcDocLine = pcDocLine->GetNextLine(); } } CMemory cmemOutputBuffer; while( pcDocLine ){ ++nLineNumber; //経過通知 if(pcDocLineMgr.GetLineCount()>0 && nLineNumber%1024==0){ NotifyProgress(nLineNumber * 100 / pcDocLineMgr.GetLineCount()); // 処理中のユーザー操作を可能にする if( !::BlockingHook( NULL ) ){ throw CAppExitException(); //中断検出 } } //1行出力 -> cmemOutputBuffer { // 書き込み時のコード変換 cstrSrc -> cmemOutputBuffer EConvertResult e = pcCodeBase->UnicodeToCode( pcDocLine->_GetDocLineDataWithEOL(), &cmemOutputBuffer ); if(e==RESULT_LOSESOME){ if(nRetVal==RESULT_COMPLETE)nRetVal=RESULT_LOSESOME; } if(e==RESULT_FAILURE){ nRetVal=RESULT_FAILURE; ErrorMessage( CEditWnd::getInstance()->GetHwnd(), LS(STR_FILESAVE_CONVERT_ERROR), sSaveInfo.cFilePath.c_str() ); break; } } //ファイルに出力 cmemOutputBuffer -> fp out.Write(cmemOutputBuffer.GetRawPtr(), cmemOutputBuffer.GetRawLength()); //次の行へ pcDocLine = pcDocLine->GetNextLine(); } //ファイルクローズ out.Close(); } catch(CError_FileOpen){ //########### 現時点では、この例外が発生した場合は正常に動作できない ErrorMessage( CEditWnd::getInstance()->GetHwnd(), LS(STR_SAVEAGENT_OTHER_APP), sSaveInfo.cFilePath.c_str() ); nRetVal = RESULT_FAILURE; } catch(CError_FileWrite){ nRetVal = RESULT_FAILURE; } catch(CAppExitException){ //中断検出 return RESULT_FAILURE; } return nRetVal; }