OSDN Git Service

プロフィール画面へのD&Dによるアイコン変更時に確認ダイアログを表示するように変更
[opentween/open-tween.git] / OpenTween / MyCommon.cs
1 // OpenTween - Client of Twitter
2 // Copyright (c) 2007-2011 kiri_feather (@kiri_feather) <kiri.feather@gmail.com>
3 //           (c) 2008-2011 Moz (@syo68k)
4 //           (c) 2008-2011 takeshik (@takeshik) <http://www.takeshik.org/>
5 //           (c) 2010-2011 anis774 (@anis774) <http://d.hatena.ne.jp/anis774/>
6 //           (c) 2010-2011 fantasticswallow (@f_swallow) <http://twitter.com/f_swallow>
7 //           (c) 2011      Egtra (@egtra) <http://dev.activebasic.com/egtra/>
8 //           (c) 2011      kim_upsilon (@kim_upsilon) <https://upsilo.net/~upsilon/>
9 // All rights reserved.
10 // 
11 // This file is part of OpenTween.
12 // 
13 // This program is free software; you can redistribute it and/or modify it
14 // under the terms of the GNU General public License as published by the Free
15 // Software Foundation; either version 3 of the License, or (at your option)
16 // any later version.
17 // 
18 // This program is distributed in the hope that it will be useful, but
19 // WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
20 // or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General public License
21 // for more details. 
22 // 
23 // You should have received a copy of the GNU General public License along
24 // with this program. if not, see <http://www.gnu.org/licenses/>, or write to
25 // the Free Software Foundation, Inc., 51 Franklin Street - Fifth Floor,
26 // Boston, MA 02110-1301, USA.
27
28 using System;
29 using System.Collections.Generic;
30 using System.Linq;
31 using System.Text;
32 using System.IO;
33 using System.Windows.Forms;
34 using System.Web;
35 using System.Globalization;
36 using System.Security.Cryptography;
37 using System.Drawing;
38 using System.Drawing.Imaging;
39 using System.Collections;
40 using System.Security.Principal;
41 using System.Runtime.Serialization.Json;
42 using System.Reflection;
43 using System.Diagnostics;
44 using System.Text.RegularExpressions;
45 using System.Net;
46 using System.Net.Http;
47 using System.Net.NetworkInformation;
48 using System.Runtime.InteropServices;
49 using OpenTween.Api;
50
51 namespace OpenTween
52 {
53     public static class MyCommon
54     {
55         private static readonly object LockObj = new object();
56         public static bool _endingFlag;        //終了フラグ
57         public static string cultureStr = null;
58         public static string settingPath;
59
60         public enum IconSizes
61         {
62             IconNone = 0,
63             Icon16 = 1,
64             Icon24 = 2,
65             Icon48 = 3,
66             Icon48_2 = 4,
67         }
68
69         public enum NameBalloonEnum
70         {
71             None,
72             UserID,
73             NickName,
74         }
75
76         public enum DispTitleEnum
77         {
78             None,
79             Ver,
80             Post,
81             UnreadRepCount,
82             UnreadAllCount,
83             UnreadAllRepCount,
84             UnreadCountAllCount,
85             OwnStatus,
86         }
87
88         public enum LogUnitEnum
89         {
90             Minute,
91             Hour,
92             Day,
93         }
94
95         public enum UploadFileType
96         {
97             Invalid,
98             Picture,
99             MultiMedia,
100         }
101
102         public enum UrlConverter
103         {
104             TinyUrl,
105             Isgd,
106             Twurl,
107             Bitly,
108             Jmp,
109             Uxnu,
110             //特殊
111             Nicoms,
112             //廃止
113             Unu = -1,
114         }
115
116         public enum HITRESULT
117         {
118             None,
119             Copy,
120             CopyAndMark,
121             Move,
122             Exclude,
123         }
124
125         public enum HttpTimeOut
126         {
127             MinValue = 10,
128             MaxValue = 120,
129             DefaultValue = 20,
130         }
131
132         //Backgroundworkerへ処理種別を通知するための引数用enum
133         public enum WORKERTYPE
134         {
135             Timeline,                //タイムライン取得
136             Reply,                   //返信取得
137             DirectMessegeRcv,        //受信DM取得
138             DirectMessegeSnt,        //送信DM取得
139             PostMessage,             //発言POST
140             FavAdd,                  //Fav追加
141             FavRemove,               //Fav削除
142             Follower,                //Followerリスト取得
143             Favorites,               //Fav取得
144             Retweet,                 //Retweetする
145             PublicSearch,            //公式検索
146             List,                    //Lists
147             Related,                 //関連発言
148             UserStream,              //UserStream
149             UserTimeline,            //UserTimeline
150             BlockIds,                //Blocking/ids
151             Configuration,           //Twitter Configuration読み込み
152             NoRetweetIds,            //RT非表示ユーザー取得
153             //////
154             ErrorState,              //エラー表示のみで後処理終了(認証エラー時など)
155         }
156
157         public static class DEFAULTTAB
158         {
159             public const string RECENT = "Recent";
160             public const string REPLY = "Reply";
161             public const string DM = "Direct";
162             public const string FAV = "Favorites";
163
164             //private string dummy;
165
166             //private object ReferenceEquals()
167             //{
168             //    return new object();
169             //}
170             //private object Equals()
171             //{
172             //    return new object();
173             //}
174         }
175
176         public static readonly object Block = null;
177         public static bool TraceFlag = false;
178
179 #if DEBUG
180         public static bool DebugBuild = true;
181 #else
182         public static bool DebugBuild = false;
183 #endif
184
185         public enum ACCOUNT_STATE
186         {
187             Valid,
188             Invalid,
189         }
190
191         public enum REPLY_ICONSTATE
192         {
193             None,
194             StaticIcon,
195             BlinkIcon,
196         }
197
198         [FlagsAttribute()]
199         public enum EVENTTYPE
200         {
201             None = 0,
202             Favorite = 1,
203             Unfavorite = 2,
204             Follow = 4,
205             ListMemberAdded = 8,
206             ListMemberRemoved = 16,
207             Block = 32,
208             Unblock = 64,
209             UserUpdate = 128,
210             Deleted = 256,
211             ListCreated = 512,
212             ListUpdated = 1024,
213             Unfollow = 2048,
214             ListUserSubscribed = 4096,
215             ListUserUnsubscribed = 8192,
216             ListDestroyed = 16384,
217             Mute = 32768,
218             Unmute = 65536,
219
220             All = (None | Favorite | Unfavorite | Follow | ListMemberAdded | ListMemberRemoved |
221                    Block | Unblock | UserUpdate | Deleted | ListCreated | ListUpdated | Unfollow |
222                    ListUserSubscribed | ListUserUnsubscribed | ListDestroyed |
223                    Mute | Unmute),
224         }
225
226         public static _Assembly EntryAssembly { get; internal set; }
227         public static string FileVersion { get; internal set; }
228
229         static MyCommon()
230         {
231             var assembly = Assembly.GetExecutingAssembly();
232             MyCommon.EntryAssembly = assembly;
233
234             var fileVersionAttribute = (AssemblyFileVersionAttribute)assembly
235                 .GetCustomAttributes(typeof(AssemblyFileVersionAttribute)).First();
236             MyCommon.FileVersion = fileVersionAttribute.Version;
237         }
238
239         public static string GetErrorLogPath()
240         {
241             return Path.Combine(Path.GetDirectoryName(MyCommon.EntryAssembly.Location), "ErrorLogs");
242         }
243
244         public static void TraceOut(WebApiException ex)
245         {
246             var message = ExceptionOutMessage(ex);
247
248             if (ex.ResponseText != null)
249                 message += Environment.NewLine + "------- Response Data -------" + Environment.NewLine + ex.ResponseText;
250
251             TraceOut(TraceFlag, message);
252         }
253
254         public static void TraceOut(Exception ex, string Message)
255         {
256             var buf = ExceptionOutMessage(ex);
257             TraceOut(TraceFlag, Message + Environment.NewLine + buf);
258         }
259
260         public static void TraceOut(string Message)
261         {
262             TraceOut(TraceFlag, Message);
263         }
264
265         public static void TraceOut(bool OutputFlag, string Message)
266         {
267             lock (LockObj)
268             {
269                 if (!OutputFlag) return;
270
271                 var logPath = MyCommon.GetErrorLogPath();
272                 if (!Directory.Exists(logPath))
273                     Directory.CreateDirectory(logPath);
274
275                 var now = DateTime.Now;
276                 var fileName = string.Format("{0}Trace-{1:0000}{2:00}{3:00}-{4:00}{5:00}{6:00}.log", GetAssemblyName(), now.Year, now.Month, now.Day, now.Hour, now.Minute, now.Second);
277                 fileName = Path.Combine(logPath, fileName);
278
279                 using (var writer = new StreamWriter(fileName))
280                 {
281                     writer.WriteLine("**** TraceOut: {0} ****", DateTime.Now.ToString());
282                     writer.WriteLine(Properties.Resources.TraceOutText1, ApplicationSettings.FeedbackEmailAddress);
283                     writer.WriteLine(Properties.Resources.TraceOutText2, ApplicationSettings.FeedbackTwitterName);
284                     writer.WriteLine();
285                     writer.WriteLine(Properties.Resources.TraceOutText3);
286                     writer.WriteLine(Properties.Resources.TraceOutText4, Environment.OSVersion.VersionString);
287                     writer.WriteLine(Properties.Resources.TraceOutText5, Environment.Version.ToString());
288                     writer.WriteLine(Properties.Resources.TraceOutText6, MyCommon.GetAssemblyName(), FileVersion);
289                     writer.WriteLine(Message);
290                     writer.WriteLine();
291                 }
292             }
293         }
294
295         // エラー内容をバッファに書き出し
296         // 注意:最終的にファイル出力されるエラーログに記録されるため次の情報は書き出さない
297         // 文頭メッセージ、権限、動作環境
298         // Dataプロパティにある終了許可フラグのパースもここで行う
299
300         public static string ExceptionOutMessage(Exception ex)
301         {
302             bool IsTerminatePermission = true;
303             return ExceptionOutMessage(ex, ref IsTerminatePermission);
304         }
305
306         public static string ExceptionOutMessage(Exception ex, ref bool IsTerminatePermission)
307         {
308             if (ex == null) return "";
309
310             var buf = new StringBuilder();
311
312             buf.AppendFormat(Properties.Resources.UnhandledExceptionText8, ex.GetType().FullName, ex.Message);
313             buf.AppendLine();
314             if (ex.Data != null)
315             {
316                 var needHeader = true;
317                 foreach (DictionaryEntry dt in ex.Data)
318                 {
319                     if (needHeader)
320                     {
321                         buf.AppendLine();
322                         buf.AppendLine("-------Extra Information-------");
323                         needHeader = false;
324                     }
325                     buf.AppendFormat("{0}  :  {1}", dt.Key, dt.Value);
326                     buf.AppendLine();
327                     if (dt.Key.Equals("IsTerminatePermission"))
328                     {
329                         IsTerminatePermission = (bool)dt.Value;
330                     }
331                 }
332                 if (!needHeader)
333                 {
334                     buf.AppendLine("-----End Extra Information-----");
335                 }
336             }
337             buf.AppendLine(ex.StackTrace);
338             buf.AppendLine();
339
340             //InnerExceptionが存在する場合書き出す
341             var _ex = ex.InnerException;
342             var nesting = 0;
343             while (_ex != null)
344             {
345                 buf.AppendFormat("-----InnerException[{0}]-----\r\n", nesting);
346                 buf.AppendLine();
347                 buf.AppendFormat(Properties.Resources.UnhandledExceptionText8, _ex.GetType().FullName, _ex.Message);
348                 buf.AppendLine();
349                 if (_ex.Data != null)
350                 {
351                     var needHeader = true;
352
353                     foreach (DictionaryEntry dt in _ex.Data)
354                     {
355                         if (needHeader)
356                         {
357                             buf.AppendLine();
358                             buf.AppendLine("-------Extra Information-------");
359                             needHeader = false;
360                         }
361                         buf.AppendFormat("{0}  :  {1}", dt.Key, dt.Value);
362                         if (dt.Key.Equals("IsTerminatePermission"))
363                         {
364                             IsTerminatePermission = (bool)dt.Value;
365                         }
366                     }
367                     if (!needHeader)
368                     {
369                         buf.AppendLine("-----End Extra Information-----");
370                     }
371                 }
372                 buf.AppendLine(_ex.StackTrace);
373                 buf.AppendLine();
374                 nesting++;
375                 _ex = _ex.InnerException;
376             }
377             return buf.ToString();
378         }
379
380         public static bool ExceptionOut(Exception ex)
381         {
382             lock (LockObj)
383             {
384                 var IsTerminatePermission = true;
385
386                 var logPath = MyCommon.GetErrorLogPath();
387                 if (!Directory.Exists(logPath))
388                     Directory.CreateDirectory(logPath);
389
390                 var now = DateTime.Now;
391                 var fileName = string.Format("{0}-{1:0000}{2:00}{3:00}-{4:00}{5:00}{6:00}.log", GetAssemblyName(), now.Year, now.Month, now.Day, now.Hour, now.Minute, now.Second);
392                 fileName = Path.Combine(logPath, fileName);
393
394                 using (var writer = new StreamWriter(fileName))
395                 {
396                     var ident = WindowsIdentity.GetCurrent();
397                     var princ = new WindowsPrincipal(ident);
398
399                     writer.WriteLine(Properties.Resources.UnhandledExceptionText1, DateTime.Now.ToString());
400                     writer.WriteLine(Properties.Resources.UnhandledExceptionText2, ApplicationSettings.FeedbackEmailAddress);
401                     writer.WriteLine(Properties.Resources.UnhandledExceptionText3, ApplicationSettings.FeedbackTwitterName);
402                     // 権限書き出し
403                     writer.WriteLine(Properties.Resources.UnhandledExceptionText11 + princ.IsInRole(WindowsBuiltInRole.Administrator).ToString());
404                     writer.WriteLine(Properties.Resources.UnhandledExceptionText12 + princ.IsInRole(WindowsBuiltInRole.User).ToString());
405                     writer.WriteLine();
406                     // OSVersion,AppVersion書き出し
407                     writer.WriteLine(Properties.Resources.UnhandledExceptionText4);
408                     writer.WriteLine(Properties.Resources.UnhandledExceptionText5, Environment.OSVersion.VersionString);
409                     writer.WriteLine(Properties.Resources.UnhandledExceptionText6, Environment.Version.ToString());
410                     writer.WriteLine(Properties.Resources.UnhandledExceptionText7, MyCommon.GetAssemblyName(), FileVersion);
411
412                     writer.Write(ExceptionOutMessage(ex, ref IsTerminatePermission));
413                     writer.Flush();
414                 }
415
416                 switch (MessageBox.Show(MyCommon.ReplaceAppName(string.Format(Properties.Resources.UnhandledExceptionText9, fileName, ApplicationSettings.FeedbackEmailAddress, ApplicationSettings.FeedbackTwitterName, Environment.NewLine)),
417                                    Properties.Resources.UnhandledExceptionText10, MessageBoxButtons.YesNoCancel, MessageBoxIcon.Error))
418                 {
419                     case DialogResult.Yes:
420                         Process.Start(fileName);
421                         return false;
422                     case DialogResult.No:
423                         return false;
424                     case DialogResult.Cancel:
425                     default:
426                         return IsTerminatePermission;
427                 }
428             }
429         }
430
431         /// <summary>
432         /// URLに含まれているマルチバイト文字列を%xx形式でエンコードします。
433         /// <newpara>
434         /// マルチバイト文字のコードはUTF-8またはUnicodeで自動的に判断します。
435         /// </newpara>
436         /// </summary>
437         /// <param name="_input">エンコード対象のURL</param>
438         /// <returns>マルチバイト文字の部分をUTF-8/%xx形式でエンコードした文字列を返します。</returns>
439
440         public static string urlEncodeMultibyteChar(string _input)
441         {
442             Uri uri = null;
443             var sb = new StringBuilder(256);
444             var result = "";
445             var c_ = 'd';
446             foreach (var c in _input)
447             {
448                 c_ = c;
449                 if (Convert.ToInt32(c) > 127 || c == '%') break;
450             }
451             if (Convert.ToInt32(c_) <= 127 && c_ != '%') return _input;
452
453             var input = Uri.UnescapeDataString(_input);
454         retry:
455             foreach (char c in input)
456             {
457                 if (Convert.ToInt32(c) > 255)
458                 {
459                     // Unicodeの場合(1charが複数のバイトで構成されている)
460                     // Uriクラスをnewして再構成し、入力をPathAndQueryのみとしてやり直す
461                     foreach (var b in Encoding.UTF8.GetBytes(c.ToString()))
462                     {
463                         sb.AppendFormat("%{0:X2}", b);
464                     }
465                 }
466                 else if (Convert.ToInt32(c) > 127 || c == '%')
467                 {
468                     // UTF-8の場合
469                     // Uriクラスをnewして再構成し、入力をinputからAuthority部分を除去してやり直す
470                     if (uri == null)
471                     {
472                         uri = new Uri(input);
473                         input = input.Remove(0, uri.GetLeftPart(UriPartial.Authority).Length);
474                         sb.Length = 0;
475                         goto retry;
476                     }
477                     else
478                     {
479                         sb.Append("%" + Convert.ToInt16(c).ToString("X2").ToUpper());
480                     }
481                 }
482                 else
483                 {
484                     sb.Append(c);
485                 }
486             }
487
488             if (uri == null)
489             {
490                 result = sb.ToString();
491             }
492             else
493             {
494                 result = uri.GetLeftPart(UriPartial.Authority) + sb.ToString();
495             }
496
497             return result;
498         }
499
500         /// <summary>
501         /// URLのドメイン名をPunycode展開します。
502         /// <para>
503         /// ドメイン名がIDNでない場合はそのまま返します。
504         /// ドメインラベルの区切り文字はFULLSTOP(.、U002E)に置き換えられます。
505         /// </para>
506         /// </summary>
507         /// <param name="input">展開対象のURL</param>
508         /// <returns>IDNが含まれていた場合はPunycodeに展開したURLをを返します。Punycode展開時にエラーが発生した場合はnullを返します。</returns>
509         public static string IDNEncode(string inputUrl)
510         {
511             try
512             {
513                 var uriBuilder = new UriBuilder(inputUrl);
514
515                 var idnConverter = new IdnMapping();
516                 uriBuilder.Host = idnConverter.GetAscii(uriBuilder.Host);
517
518                 return uriBuilder.Uri.ToString();
519             }
520             catch (Exception)
521             {
522                 return null;
523             }
524         }
525
526         public static string IDNDecode(string inputUrl)
527         {
528             try
529             {
530                 var uriBuilder = new UriBuilder(inputUrl);
531
532                 if (uriBuilder.Host != null)
533                 {
534                     var idnConverter = new IdnMapping();
535                     uriBuilder.Host = idnConverter.GetUnicode(uriBuilder.Host);
536                 }
537
538                 return uriBuilder.Uri.ToString();
539             }
540             catch (Exception)
541             {
542                 return null;
543             }
544         }
545
546         /// <summary>
547         /// URL を画面上で人間に読みやすい文字列に変換する(エスケープ解除など)
548         /// </summary>
549         public static string ConvertToReadableUrl(string inputUrl)
550         {
551             try
552             {
553                 var outputUrl = inputUrl;
554
555                 // Punycodeをデコードする
556                 outputUrl = MyCommon.IDNDecode(outputUrl);
557                 if (outputUrl == null)
558                     return inputUrl;
559
560                 // URL内で特殊な意味を持つ記号は元の文字に変換されることを避けるために二重エスケープする
561                 // 参考: Firefoxの losslessDecodeURI() 関数
562                 //   http://hg.mozilla.org/mozilla-central/annotate/FIREFOX_AURORA_27_BASE/browser/base/content/browser.js#l2128
563                 outputUrl = Regex.Replace(outputUrl, @"%(2[3456BCF]|3[ABDF]|40)", @"%25$1", RegexOptions.IgnoreCase);
564
565                 // エスケープを解除する
566                 outputUrl = Uri.UnescapeDataString(outputUrl);
567
568                 return outputUrl;
569             }
570             catch (UriFormatException)
571             {
572                 return inputUrl;
573             }
574         }
575
576         public static void MoveArrayItem(int[] values, int idx_fr, int idx_to)
577         {
578             var moved_value = values[idx_fr];
579             var num_moved = Math.Abs(idx_fr - idx_to);
580
581             if (idx_to < idx_fr)
582             {
583                 Array.Copy(values, idx_to, values,
584                     idx_to + 1, num_moved);
585             }
586             else
587             {
588                 Array.Copy(values, idx_fr + 1, values,
589                     idx_fr, num_moved);
590             }
591
592             values[idx_to] = moved_value;
593         }
594
595         public static string EncryptString(string str)
596         {
597             if (string.IsNullOrEmpty(str)) return "";
598
599             //文字列をバイト型配列にする
600             var bytesIn = Encoding.UTF8.GetBytes(str);
601
602             //DESCryptoServiceProviderオブジェクトの作成
603             using (var des = new DESCryptoServiceProvider())
604             {
605                 //共有キーと初期化ベクタを決定
606                 //パスワードをバイト配列にする
607                 var bytesKey = Encoding.UTF8.GetBytes("_tween_encrypt_key_");
608                 //共有キーと初期化ベクタを設定
609                 des.Key = ResizeBytesArray(bytesKey, des.Key.Length);
610                 des.IV = ResizeBytesArray(bytesKey, des.IV.Length);
611
612                 MemoryStream msOut = null;
613                 ICryptoTransform desdecrypt = null;
614
615                 try
616                 {
617                     //暗号化されたデータを書き出すためのMemoryStream
618                     msOut = new MemoryStream();
619
620                     //DES暗号化オブジェクトの作成
621                     desdecrypt = des.CreateEncryptor();
622
623                     //書き込むためのCryptoStreamの作成
624                     using (CryptoStream cryptStream = new CryptoStream(msOut, desdecrypt, CryptoStreamMode.Write))
625                     {
626                         //Disposeが重複して呼ばれないようにする
627                         MemoryStream msTmp = msOut;
628                         msOut = null;
629                         desdecrypt = null;
630
631                         //書き込む
632                         cryptStream.Write(bytesIn, 0, bytesIn.Length);
633                         cryptStream.FlushFinalBlock();
634                         //暗号化されたデータを取得
635                         var bytesOut = msTmp.ToArray();
636
637                         //Base64で文字列に変更して結果を返す
638                         return Convert.ToBase64String(bytesOut);
639                     }
640                 }
641                 finally
642                 {
643                     if (msOut != null) msOut.Dispose();
644                     if (desdecrypt != null) desdecrypt.Dispose();
645                 }
646             }
647         }
648
649         public static string DecryptString(string str)
650         {
651             if (string.IsNullOrEmpty(str)) return "";
652
653             //DESCryptoServiceProviderオブジェクトの作成
654             using (var des = new System.Security.Cryptography.DESCryptoServiceProvider())
655             {
656                 //共有キーと初期化ベクタを決定
657                 //パスワードをバイト配列にする
658                 var bytesKey = Encoding.UTF8.GetBytes("_tween_encrypt_key_");
659                 //共有キーと初期化ベクタを設定
660                 des.Key = ResizeBytesArray(bytesKey, des.Key.Length);
661                 des.IV = ResizeBytesArray(bytesKey, des.IV.Length);
662
663                 //Base64で文字列をバイト配列に戻す
664                 var bytesIn = Convert.FromBase64String(str);
665
666                 MemoryStream msIn = null;
667                 ICryptoTransform desdecrypt = null;
668                 CryptoStream cryptStreem = null;
669
670                 try
671                 {
672                     //暗号化されたデータを読み込むためのMemoryStream
673                     msIn = new MemoryStream(bytesIn);
674                     //DES復号化オブジェクトの作成
675                     desdecrypt = des.CreateDecryptor();
676                     //読み込むためのCryptoStreamの作成
677                     cryptStreem = new CryptoStream(msIn, desdecrypt, CryptoStreamMode.Read);
678
679                     //Disposeが重複して呼ばれないようにする
680                     msIn = null;
681                     desdecrypt = null;
682
683                     //復号化されたデータを取得するためのStreamReader
684                     using (StreamReader srOut = new StreamReader(cryptStreem, Encoding.UTF8))
685                     {
686                         //Disposeが重複して呼ばれないようにする
687                         cryptStreem = null;
688
689                         //復号化されたデータを取得する
690                         var result = srOut.ReadToEnd();
691
692                         return result;
693                     }
694                 }
695                 finally
696                 {
697                     if (msIn != null) msIn.Dispose();
698                     if (desdecrypt != null) desdecrypt.Dispose();
699                     if (cryptStreem != null) cryptStreem.Dispose();
700                 }
701             }
702         }
703
704         public static byte[] ResizeBytesArray(byte[] bytes,
705                                     int newSize)
706         {
707             var newBytes = new byte[newSize];
708             if (bytes.Length <= newSize)
709             {
710                 foreach (var i in Enumerable.Range(0, bytes.Length))
711                 {
712                     newBytes[i] = bytes[i];
713                 }
714             }
715             else
716             {
717                 var pos = 0;
718                 foreach (var i in Enumerable.Range(0, bytes.Length))
719                 {
720                     newBytes[pos] = unchecked((byte)(newBytes[pos] ^ bytes[i]));
721                     pos++;
722                     if (pos >= newBytes.Length)
723                     {
724                         pos = 0;
725                     }
726                 }
727             }
728             return newBytes;
729         }
730
731         public static bool IsNT6()
732         {
733             //NT6 kernelかどうか検査
734             return Environment.OSVersion.Platform == PlatformID.Win32NT && Environment.OSVersion.Version.Major == 6;
735         }
736
737         [FlagsAttribute()]
738         public enum TabUsageType
739         {
740             Undefined = 0,
741             Home = 1,      //Unique
742             Mentions = 2,     //Unique
743             DirectMessage = 4,   //Unique
744             Favorites = 8,       //Unique
745             UserDefined = 16,
746             LocalQuery = 32,      //Pin(no save/no save query/distribute/no update(normal update))
747             Profile = 64,         //Pin(save/no distribute/manual update)
748             PublicSearch = 128,    //Pin(save/no distribute/auto update)
749             Lists = 256,
750             Related = 512,
751             UserTimeline = 1024,
752             //RTMyTweet
753             //RTByOthers
754             //RTByMe
755         }
756
757         public static TwitterApiStatus TwitterApiInfo = new TwitterApiStatus();
758
759         public static bool IsAnimatedGif(string filename)
760         {
761             Image img = null;
762             try
763             {
764                 img = Image.FromFile(filename);
765                 if (img == null) return false;
766                 if (img.RawFormat.Guid == ImageFormat.Gif.Guid)
767                 {
768                     var fd = new FrameDimension(img.FrameDimensionsList[0]);
769                     var fd_count = img.GetFrameCount(fd);
770                     if (fd_count > 1)
771                     {
772                         return true;
773                     }
774                     else
775                     {
776                         return false;
777                     }
778                 }
779                 return false;
780             }
781             catch (Exception)
782             {
783                 return false;
784             }
785             finally
786             {
787                 if (img != null) img.Dispose();
788             }
789         }
790
791         public static DateTime DateTimeParse(string input)
792         {
793             DateTime rslt;
794             string[] format = {
795                 "ddd MMM dd HH:mm:ss zzzz yyyy",
796                 "ddd, d MMM yyyy HH:mm:ss zzzz",
797             };
798             foreach (var fmt in format)
799             {
800                 if (DateTime.TryParseExact(input,
801                                           fmt,
802                                           DateTimeFormatInfo.InvariantInfo,
803                                           DateTimeStyles.None,
804                                           out rslt))
805                 {
806                     return rslt;
807                 }
808                 else
809                 {
810                     continue;
811                 }
812             }
813             TraceOut("Parse Error(DateTimeFormat) : " + input);
814             return new DateTime();
815         }
816
817         public static T CreateDataFromJson<T>(string content)
818         {
819             T data;
820             var buf = Encoding.Unicode.GetBytes(content);
821             using (var stream = new MemoryStream(buf))
822             {
823                 data = (T)((new DataContractJsonSerializer(typeof(T))).ReadObject(stream));
824             }
825             return data;
826         }
827
828         public static bool IsNetworkAvailable()
829         {
830             try
831             {
832                 return NetworkInterface.GetIsNetworkAvailable();
833             }
834             catch(Exception)
835             {
836                 return false;
837             }
838         }
839
840         public static bool IsValidEmail(string strIn)
841         {
842             // Return true if strIn is in valid e-mail format.
843             return Regex.IsMatch(strIn,
844                    @"^(?("")("".+?""@)|(([0-9a-zA-Z]((\.(?!\.))|[-!#\$%&'\*\+/=\?\^`\{\}\|~\w])*)(?<=[0-9a-zA-Z])@))" +
845                    @"(?(\[)(\[(\d{1,3}\.){3}\d{1,3}\])|(([0-9a-zA-Z][-\w]*[0-9a-zA-Z]\.)+[a-zA-Z]{2,6}))$");
846         }
847
848         /// <summary>
849         /// 指定された修飾キーが押されている状態かを取得します。
850         /// </summary>
851         /// <param name="keys">状態を調べるキー</param>
852         /// <returns><paramref name="keys"/> で指定された修飾キーがすべて押されている状態であれば true。それ以外であれば false。</returns>
853         public static bool IsKeyDown(params Keys[] keys)
854         {
855             return MyCommon._IsKeyDown(Control.ModifierKeys, keys);
856         }
857
858         internal static bool _IsKeyDown(Keys modifierKeys, Keys[] targetKeys)
859         {
860             foreach (Keys key in targetKeys)
861             {
862                 if ((modifierKeys & key) != key)
863                 {
864                     return false;
865                 }
866             }
867             return true;
868         }
869
870         /// <summary>
871         /// アプリケーションのアセンブリ名を取得します。
872         /// </summary>
873         /// <remarks>
874         /// VB.NETの<code>My.Application.Info.AssemblyName</code>と(ほぼ)同じ動作をします。
875         /// </remarks>
876         /// <returns>アプリケーションのアセンブリ名</returns>
877         public static string GetAssemblyName()
878         {
879             return MyCommon.EntryAssembly.GetName().Name;
880         }
881
882         /// <summary>
883         /// 文字列中に含まれる %AppName% をアプリケーション名に置換する
884         /// </summary>
885         /// <param name="orig">対象となる文字列</param>
886         /// <returns>置換後の文字列</returns>
887         public static string ReplaceAppName(string orig)
888         {
889             return MyCommon.ReplaceAppName(orig, Application.ProductName);
890         }
891
892         /// <summary>
893         /// 文字列中に含まれる %AppName% をアプリケーション名に置換する
894         /// </summary>
895         /// <param name="orig">対象となる文字列</param>
896         /// <param name="appname">アプリケーション名</param>
897         /// <returns>置換後の文字列</returns>
898         public static string ReplaceAppName(string orig, string appname)
899         {
900             return orig.Replace("%AppName%", appname);
901         }
902
903         /// <summary>
904         /// 表示用のバージョン番号の文字列を生成する
905         /// </summary>
906         /// <remarks>
907         /// バージョン1.0.0.1のように末尾が0でない(=開発版)の場合は「1.0.1-beta1」が出力される
908         /// </remarks>
909         /// <returns>
910         /// 生成されたバージョン番号の文字列
911         /// </returns>
912         public static string GetReadableVersion(string versionStr = null)
913         {
914             var version = Version.Parse(versionStr ?? MyCommon.FileVersion);
915
916             return GetReadableVersion(version);
917         }
918
919         /// <summary>
920         /// 表示用のバージョン番号の文字列を生成する
921         /// </summary>
922         /// <remarks>
923         /// バージョン1.0.0.1のように末尾が0でない(=開発版)の場合は「1.0.1-beta1」が出力される
924         /// </remarks>
925         /// <returns>
926         /// 生成されたバージョン番号の文字列
927         /// </returns>
928         public static string GetReadableVersion(Version version)
929         {
930             var versionNum = new[] { version.Major, version.Minor, version.Build, version.Revision };
931
932             if (versionNum[3] == 0)
933             {
934                 return string.Format("{0}.{1}.{2}", versionNum[0], versionNum[1], versionNum[2]);
935             }
936             else
937             {
938                 versionNum[2] = versionNum[2] + 1;
939
940                 // 10を越えたら桁上げ
941                 if (versionNum[2] >= 10)
942                 {
943                     versionNum[1] += versionNum[2] / 10;
944                     versionNum[2] %= 10;
945
946                     if (versionNum[1] >= 10)
947                     {
948                         versionNum[0] += versionNum[1] / 10;
949                         versionNum[1] %= 10;
950                     }
951                 }
952
953                 return string.Format("{0}.{1}.{2}-beta{3}", versionNum[0], versionNum[1], versionNum[2], versionNum[3]);
954             }
955         }
956
957         public const string TwitterUrl = "https://twitter.com/";
958
959         public static string GetStatusUrl(PostClass post)
960         {
961             if (post.RetweetedId == null)
962                 return GetStatusUrl(post.ScreenName, post.StatusId);
963             else
964                 return GetStatusUrl(post.ScreenName, post.RetweetedId.Value);
965         }
966
967         public static string GetStatusUrl(string screenName, long statusId)
968         {
969             return TwitterUrl + screenName + "/status/" + statusId.ToString();
970         }
971
972         /// <summary>
973         /// 指定された IDictionary を元にクエリ文字列を生成します
974         /// </summary>
975         /// <param name="param">生成するクエリの key-value コレクション</param>
976         public static string BuildQueryString(IDictionary<string, string> param)
977         {
978             if (param == null || param.Count == 0)
979                 return string.Empty;
980
981             var query = param
982                 .Where(x => x.Value != null)
983                 .Select(x => EscapeQueryString(x.Key) + '=' + EscapeQueryString(x.Value));
984
985             return string.Join("&", query);
986         }
987
988         // .NET 4.5+: Reserved characters のうち、Uriクラスによってエスケープ強制解除されてしまうものも最初から Unreserved として扱う
989         private static readonly HashSet<char> UnreservedChars =
990             new HashSet<char>("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-_.~!'()*:");
991
992         /// <summary>
993         /// 2バイト文字も考慮したクエリ用エンコード
994         /// </summary>
995         /// <param name="stringToEncode">エンコードする文字列</param>
996         /// <returns>エンコード結果文字列</returns>
997         public static string EscapeQueryString(string stringToEncode)
998         {
999             var sb = new StringBuilder(stringToEncode.Length * 2);
1000
1001             foreach (var b in Encoding.UTF8.GetBytes(stringToEncode))
1002             {
1003                 if (UnreservedChars.Contains((char)b))
1004                     sb.Append((char)b);
1005                 else
1006                     sb.AppendFormat("%{0:X2}", b);
1007             }
1008
1009             return sb.ToString();
1010         }
1011
1012         /// <summary>
1013         /// 指定された範囲の整数を昇順に列挙します
1014         /// </summary>
1015         /// <remarks>
1016         /// start, start + 1, start + 2, ..., end の範囲の数列を生成します
1017         /// </remarks>
1018         /// <param name="from">数列の先頭の値 (最小値)</param>
1019         /// <param name="to">数列の末尾の値 (最大値)</param>
1020         /// <returns>整数を列挙する IEnumerable インスタンス</returns>
1021         public static IEnumerable<int> CountUp(int from, int to)
1022         {
1023             if (from > to)
1024                 return Enumerable.Empty<int>();
1025
1026             return Enumerable.Range(from, to - from + 1);
1027         }
1028
1029         /// <summary>
1030         /// 指定された範囲の整数を降順に列挙します
1031         /// </summary>
1032         /// <remarks>
1033         /// start, start - 1, start - 2, ..., end の範囲の数列を生成します
1034         /// </remarks>
1035         /// <param name="from">数列の先頭の値 (最大値)</param>
1036         /// <param name="to">数列の末尾の値 (最小値)</param>
1037         /// <returns>整数を列挙する IEnumerable インスタンス</returns>
1038         public static IEnumerable<int> CountDown(int from, int to)
1039         {
1040             for (var i = from; i >= to; i--)
1041                 yield return i;
1042         }
1043     }
1044 }