/// <summary> /// zipファイル内のファイル名を指定しての読み込み。 /// </summary> /// <param name="filename">zipファイル名</param> /// <param name="innerFileName">zip内のファイル名</param> /// <param name="bRead">読み込むのか?読み込むときはbuffにその内容が返る</param> /// <param name="buff"></param> /// <returns> /// bRead=falseのとき、ヘッダ内に該当ファイルが存在すればtrue /// bRead=trueのとき、読み込みが成功すればtrue /// </returns> /// <summary> /// zipファイル内のファイル名を指定しての読み込み。 /// /// 大文字小文字の違いは無視する。 /// </summary> /// <param name="filename">zipファイル名</param> /// <param name="innerFileName">zip内のファイル名</param> /// <param name="bRead">読み込むのか?読み込むときはbuffにその内容が返る</param> /// <param name="buff"></param> /// <returns> /// bRead=falseのとき、ヘッダ内に該当ファイルが存在すればtrue /// bRead=trueのとき、読み込みが成功すればtrue /// </returns> public bool Read(string filename , string innerFileName , bool bRead , out byte[] buff) { // .NET Framework2.0には System.Io.CompressionにGZipStreamというクラスがある。 // これはZipStreamを扱うクラスなのでファイルを扱う部分は自前で用意してやる必要がある // cf. // http://msdn2.microsoft.com/en-us/library/zs4f0x23.aspx buff = null; if ( ! reader.IsExist(filename) ) goto Exit; Stream file = reader.Read(filename); if ( file == null ) goto Exit; // おそらくは存在しないか二重openか。 // 二重openできないので、使いおわったら必ずCloseしなくてはならない。 // そのためにtry~finallyで括ることにする。 try { StreamRandAccessor acc = new StreamRandAccessor(file); Dictionary<string,object> cacheList = null; // 読み込みcacheが有効らしい if ( readCache ) { filename = filename.ToLower(); if ( arcFileList.IsExistArchive(filename) ) { // このarcFileListのなかから探し出す // 格納されているファイル名をToLower等で正規化しておく必要あり object obj; try { innerFileName = innerFileName.ToLower(); obj = arcFileList.ArchiveList[filename][innerFileName]; } catch { return false; // 見つからない } // ここで取得したobjを元にファイルから読み込む InnerZipFileInfo info = obj as InnerZipFileInfo; uint localHeaderPos = info.localHeaderPos; uint compressed_size = info.compressed_size; uint uncompressed_size = info.uncompressed_size; return innerExtract(acc , localHeaderPos , bRead , compressed_size , uncompressed_size , out buff); } // このファイルにファイルリスト読み込むのが先決では… cacheList= new Dictionary<string,object>(); arcFileList.ArchiveList.Add(filename,cacheList); } // Find 'end record index' by searching backwards for signature long stoppos; // ulongって引き算とか比較が面倒くさいですなぁ..(´Д`) if ( file.Length < 66000 ) { stoppos = 0; } else { stoppos = acc.Length - 66000; } long endrecOffset = 0; for ( long i = acc.Length - 22 ; i >= stoppos ; --i ) { if ( acc.GetUint(i) == 0x06054b50 ) { // "PK\0x05\0x06" ushort endcommentlength = acc.GetUshort(i + 20); if ( i + 22 + endcommentlength != acc.Length ) continue; endrecOffset = i; } goto endrecFound; } // ダメジャン goto Exit; endrecFound: ; // ---- endrecOffsetが求まったナリよ! ushort filenum = acc.GetUshort(endrecOffset + 10); // zipに格納されているファイルの数(分割zipは非対応) long c_pos = acc.GetUint(endrecOffset + 16); // central directoryの位置 // printf("filenum %d",filenum); // ---- central directoryが求まったなりよ! while ( filenum-- > 0 ) { if ( acc.GetUint(c_pos) != 0x02014b50 ) { // シグネチャー確認! goto Exit; // return false; // おかしいで、このファイル } uint compressed_size = acc.GetUint(c_pos + 20); uint uncompressed_size = acc.GetUint(c_pos + 24); ushort filename_length = acc.GetUshort(c_pos + 28); ushort extra_field_length = acc.GetUshort(c_pos + 30); ushort file_comment_length = acc.GetUshort(c_pos + 32); //printf("filenamelength : %d",filename_length); // local_header_pos uint lh_pos = acc.GetUint(c_pos + 42); // ファイル名の取得 StringBuilderEncoding fname = new StringBuilderEncoding(filename_length); for ( int i = 0 ; i < filename_length ; ++i ) { fname.Add(acc.GetByte(i + c_pos + 46)); } // printf("%.*name\n",fname); // ファイル名が得られた。 // string fullfilename = dirname + fname; // yield return fullfilename; if ( cacheList!=null ) { // readCacheが有効なら、まずは格納していく。 cacheList.Add(fname.ToString().ToLower() , new InnerZipFileInfo(lh_pos , compressed_size , uncompressed_size)); } else { // ファイル名の一致比較は、大文字小文字の違いは無視する。 // // Windows環境ではファイルシステムは、ファイルの大文字小文字の違いは無視するが、 // いざリリースのときにzipフォルダにまとめたせいでいままで動いていたものが // 動かなくなると嫌なので。 if ( fname.Convert(codePage).Equals(innerFileName , StringComparison.CurrentCultureIgnoreCase) ) { // 一致したでー!これ読み込もうぜー! return innerExtract(acc , lh_pos , bRead , compressed_size , uncompressed_size , out buff); } } // さーて、来週のサザエさんは.. c_pos += 46 + filename_length + extra_field_length + file_comment_length; } } finally { if ( file != null ) file.Dispose(); } // readCacheが有効なのに、ここまで到達するというのは、 // archive内のfile listをcacheしていなかったので調べていたに違いない。 // よって、再帰的に呼び出すことによって解決できる。 if ( readCache ) return Read(filename , innerFileName , bRead , out buff); Exit: ; buff = null; return false; }
public override IEnumerator GetEnumerator() { // ZipStream zip = new GZipStream(filename); // foreach (ZipEntry e in zip) { // yield return e.Name; // } Stream file = null; if ( !reader.IsExist(filename) ) goto Exit; file = reader.Read(filename); if ( file == null ) goto Exit; // おそらくは存在しないか二重openか。 StreamRandAccessor acc = new StreamRandAccessor(file); // Find 'end record index' by searching backwards for signature long stoppos; // ulongって引き算とか比較が面倒くさいですなぁ..(´Д`) if ( file.Length < 66000 ) { stoppos = 0; } else { stoppos = acc.Length - 66000; } long endrecOffset = 0; for ( long i = acc.Length - 22 ; i >= stoppos ; --i ) { if ( acc.GetUint(i) == 0x06054b50 ) { // "PK\0x05\0x06" ushort endcommentlength = acc.GetUshort(i + 20); if ( i + 22 + endcommentlength != acc.Length ) continue; endrecOffset = i; } goto endrecFound; } // ダメジャン goto Exit; endrecFound: ; // ---- endrecOffsetが求まったナリよ! ushort filenum = acc.GetUshort(endrecOffset + 10); // zipに格納されているファイルの数(分割zipは非対応) long c_pos = acc.GetUint(endrecOffset + 16); // central directoryの位置 // printf("filenum %d",filenum); // ---- central directoryが求まったなりよ! while ( filenum-- > 0 ) { if ( acc.GetUint(c_pos) != 0x02014b50 ) { // シグネチャー確認! goto Exit; // return false; // おかしいで、このファイル } uint compressed_size = acc.GetUint(c_pos + 20); uint uncompressed_size = acc.GetUint(c_pos + 24); ushort filename_length = acc.GetUshort(c_pos + 28); ushort extra_field_length = acc.GetUshort(c_pos + 30); ushort file_comment_length = acc.GetUshort(c_pos + 32); //printf("filenamelength : %d",filename_length); // local_header_pos uint lh_pos = acc.GetUint(c_pos + 42); // ファイル名の取得 StringBuilderEncoding fname = new StringBuilderEncoding(filename_length); for ( int i = 0 ; i < filename_length ; ++i ) { fname.Add(acc.GetByte(i + c_pos + 46)); } // printf("%.*name\n",fname); // ファイル名が得られた。 string fullfilename = dirname + fname.Convert(codePage); yield return fullfilename; // さーて、来週のサザエさんは.. c_pos += 46 + filename_length + extra_field_length + file_comment_length; } Exit: ; if ( file != null ) file.Dispose(); }
/// <summary> /// 一行解析する /// </summary> /// <remarks> /// 行の解析のときに /// 1,2,3 // コメント /// ↑このような書き方をされる可能性がある。これを正しく解析するのは /// 結構面倒だけど対応させることにする。 /// </remarks> /// <param name="line"></param> private void Parse(StringBuilderEncoding bytes, bool BOMFound) { string line; if (BOMFound) { line = bytes.Convert(Encoding.GetEncoding("utf-16")); } else { line = bytes.Convert(codePage); } List<string> list = new List<string>(); StringBuilder atom = new StringBuilder(); // end of line判定フラグ bool eol = false; // 空行ではないのか bool valid = false; char c = default(char); // ↑warningが出ると嫌なので(´ω`) for (int i = 0; i < line.Length+1; ++i) { if (i<line.Length) c = line[i]; else eol = true; // "//"で始まるのか調べるために、'/'であれば // 一文字だけ先読みさせてもらう。 if (c == '/' && i < line.Length - 1 && line[i + 1] == '/') { // ここ以降はコメントなので、カンマに遭遇したとすれば良い。 eol = true; } if (!eol) { // 項目先頭のspaceは無視 if (atom.Length == 0 && c == ' ') continue; // 項目途中でも TAB は常にら無視 if (c == '\t') continue; } bool comma = c == ','; // 一つでもカンマがあればそれは意味のある行だとみなす if (comma) valid = true; if (comma || eol) { //↓カンマ区切りで ""を設定することがあるのでこのチェック不要。 // if (atom.Length!=0) // 末尾のspaceは削除。 while (0 < atom.Length && atom[atom.Length - 1]==' ') -- atom.Length; list.Add(atom.ToString()); // ひとつでも有効な要素があれば有効な行である if (atom.Length != 0) valid = true; atom.Length = 0; if (eol) break; // forから抜ける continue; } atom.Append(c); } if (valid) csvdata.Add(list); }
/// <summary> /// CSVファイルからデータを読み込む /// </summary> /// <example> /// CSVReader reader = new CSVReader(); /// reader.read("csv.txt"); /// reader.DebugOutput(); /// </example> /// <param name="filename"></param> /// <returns></returns> public YanesdkResult Read(string filename) { csvdata.Clear(); byte[] data = FileSys.Read(filename); if (data == null) return YanesdkResult.FileReadError; BOMFound = (data.Length >= 2 && data[0] == 0xff && data[1] == 0xfe) ; // このdataを解析していく。 StringBuilderEncoding line = new StringBuilderEncoding(); if (BOMFound) { for (int i = 2; i < data.Length;) { byte b1 = data[i++]; if (!(i < data.Length)) break; byte b2 = data[i++]; if (b2 == 0 && (b1 == 0x0a || b1 == 0x0d)) { // 一行読めたのでlineを解析 Parse(line, BOMFound); line.Clear(); } else { line.Add(b1); line.Add(b2); } } } else { foreach(byte c in data) { if (c == 0x0a || c == 0x0d) { // 一行読めたのでlineを解析 Parse(line,BOMFound); line.Clear(); } else { line.Add(c); } } } // 最後に改行なしのlineがある可能性アリ if (line.Count != 0) Parse(line, BOMFound); return YanesdkResult.NoError; }
/// <summary> /// CSVファイルからデータを読み込む /// </summary> /// <example> /// CSVReader reader = new CSVReader(); /// reader.read("csv.txt"); /// reader.DebugOutput(); /// </example> /// <param name="filename"></param> /// <returns></returns> public YanesdkResult Read(string filename) { csvdata.Clear(); byte[] data = FileSys.Read(filename); if (data == null) { return(YanesdkResult.FileReadError); } BOMFound = (data.Length >= 2 && data[0] == 0xff && data[1] == 0xfe); // このdataを解析していく。 StringBuilderEncoding line = new StringBuilderEncoding(); if (BOMFound) { for (int i = 2; i < data.Length;) { byte b1 = data[i++]; if (!(i < data.Length)) { break; } byte b2 = data[i++]; if (b2 == 0 && (b1 == 0x0a || b1 == 0x0d)) { // 一行読めたのでlineを解析 Parse(line, BOMFound); line.Clear(); } else { line.Add(b1); line.Add(b2); } } } else { foreach (byte c in data) { if (c == 0x0a || c == 0x0d) { // 一行読めたのでlineを解析 Parse(line, BOMFound); line.Clear(); } else { line.Add(c); } } } // 最後に改行なしのlineがある可能性アリ if (line.Count != 0) { Parse(line, BOMFound); } return(YanesdkResult.NoError); }
/// <summary> /// 一行解析する /// </summary> /// <remarks> /// 行の解析のときに /// 1,2,3 // コメント /// ↑このような書き方をされる可能性がある。これを正しく解析するのは /// 結構面倒だけど対応させることにする。 /// </remarks> /// <param name="line"></param> private void Parse(StringBuilderEncoding bytes, bool BOMFound) { string line; if (BOMFound) { line = bytes.Convert(Encoding.GetEncoding("utf-16")); } else { line = bytes.Convert(codePage); } List <string> list = new List <string>(); StringBuilder atom = new StringBuilder(); // end of line判定フラグ bool eol = false; // 空行ではないのか bool valid = false; char c = default(char); // ↑warningが出ると嫌なので(´ω`) for (int i = 0; i < line.Length + 1; ++i) { if (i < line.Length) { c = line[i]; } else { eol = true; } // "//"で始まるのか調べるために、'/'であれば // 一文字だけ先読みさせてもらう。 if (c == '/' && i < line.Length - 1 && line[i + 1] == '/') { // ここ以降はコメントなので、カンマに遭遇したとすれば良い。 eol = true; } if (!eol) { // 項目先頭のspaceは無視 if (atom.Length == 0 && c == ' ') { continue; } // 項目途中でも TAB は常にら無視 if (c == '\t') { continue; } } bool comma = c == ','; // 一つでもカンマがあればそれは意味のある行だとみなす if (comma) { valid = true; } if (comma || eol) { //↓カンマ区切りで ""を設定することがあるのでこのチェック不要。 // if (atom.Length!=0) // 末尾のspaceは削除。 while (0 < atom.Length && atom[atom.Length - 1] == ' ') { --atom.Length; } list.Add(atom.ToString()); // ひとつでも有効な要素があれば有効な行である if (atom.Length != 0) { valid = true; } atom.Length = 0; if (eol) { break; // forから抜ける } continue; } atom.Append(c); } if (valid) { csvdata.Add(list); } }