OSDN Git Service

検索APIをJSONに切り替え
[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.NetworkInformation;
46
47 namespace OpenTween
48 {
49     [Microsoft.VisualBasic.CompilerServices.StandardModule]
50     public sealed class MyCommon
51     {
52         private static readonly object LockObj = new object();
53         public static bool _endingFlag;        //終了フラグ
54         public static string cultureStr = null;
55         public static string settingPath;
56
57         public enum IconSizes
58         {
59             IconNone = 0,
60             Icon16 = 1,
61             Icon24 = 2,
62             Icon48 = 3,
63             Icon48_2 = 4,
64         }
65
66         public enum NameBalloonEnum
67         {
68             None,
69             UserID,
70             NickName,
71         }
72
73         public enum DispTitleEnum
74         {
75             None,
76             Ver,
77             Post,
78             UnreadRepCount,
79             UnreadAllCount,
80             UnreadAllRepCount,
81             UnreadCountAllCount,
82             OwnStatus,
83         }
84
85         public enum LogUnitEnum
86         {
87             Minute,
88             Hour,
89             Day,
90         }
91
92         public enum UploadFileType
93         {
94             Invalid,
95             Picture,
96             MultiMedia,
97         }
98
99         public enum UrlConverter
100         {
101             TinyUrl,
102             Isgd,
103             Twurl,
104             Bitly,
105             Jmp,
106             Uxnu,
107             //特殊
108             Nicoms,
109             //廃止
110             Unu = -1,
111         }
112
113         public enum OutputzUrlmode
114         {
115             twittercom,
116             twittercomWithUsername,
117         }
118
119         public enum HITRESULT
120         {
121             None,
122             Copy,
123             CopyAndMark,
124             Move,
125             Exclude,
126         }
127
128         public enum HttpTimeOut
129         {
130             MinValue = 10,
131             MaxValue = 120,
132             DefaultValue = 20,
133         }
134
135         //Backgroundworkerへ処理種別を通知するための引数用enum
136         public enum WORKERTYPE
137         {
138             Timeline,                //タイムライン取得
139             Reply,                   //返信取得
140             DirectMessegeRcv,        //受信DM取得
141             DirectMessegeSnt,        //送信DM取得
142             PostMessage,             //発言POST
143             FavAdd,                  //Fav追加
144             FavRemove,               //Fav削除
145             Follower,                //Followerリスト取得
146             OpenUri,                 //Uri開く
147             Favorites,               //Fav取得
148             Retweet,                 //Retweetする
149             PublicSearch,            //公式検索
150             List,                    //Lists
151             Related,                 //関連発言
152             UserStream,              //UserStream
153             UserTimeline,            //UserTimeline
154             BlockIds,                //Blocking/ids
155             Configuration,           //Twitter Configuration読み込み
156             //////
157             ErrorState,              //エラー表示のみで後処理終了(認証エラー時など)
158         }
159
160         public static class DEFAULTTAB
161         {
162             public const string RECENT = "Recent";
163             public const string REPLY = "Reply";
164             public const string DM = "Direct";
165             public const string FAV = "Favorites";
166
167             //private string dummy;
168
169             //private object ReferenceEquals()
170             //{
171             //    return new object();
172             //}
173             //private object Equals()
174             //{
175             //    return new object();
176             //}
177         }
178
179         public static readonly object Block = null;
180         public static bool TraceFlag = false;
181
182 #if DEBUG
183         public static bool DebugBuild = true;
184 #else
185         public static bool DebugBuild = false;
186 #endif
187
188         public enum ACCOUNT_STATE
189         {
190             Valid,
191             Invalid,
192         }
193
194         public enum REPLY_ICONSTATE
195         {
196             None,
197             StaticIcon,
198             BlinkIcon,
199         }
200
201         [FlagsAttribute()]
202         public enum EVENTTYPE
203         {
204             None = 0,
205             Favorite = 1,
206             Unfavorite = 2,
207             Follow = 4,
208             ListMemberAdded = 8,
209             ListMemberRemoved = 16,
210             Block = 32,
211             Unblock = 64,
212             UserUpdate = 128,
213             Deleted = 256,
214             ListCreated = 512,
215             ListUpdated = 1024,
216
217             All = (None | Favorite | Unfavorite | Follow | ListMemberAdded | ListMemberRemoved |
218                    Block | Unblock | UserUpdate | Deleted | ListCreated | ListUpdated),
219         }
220
221         public static void TraceOut(Exception ex, string Message)
222         {
223             var buf = ExceptionOutMessage(ex);
224             TraceOut(TraceFlag, Message + Environment.NewLine + buf);
225         }
226
227         public static void TraceOut(string Message)
228         {
229             TraceOut(TraceFlag, Message);
230         }
231
232         public static void TraceOut(bool OutputFlag, string Message)
233         {
234             lock (LockObj)
235             {
236                 if (!OutputFlag) return;
237                 var now = DateTime.Now;
238                 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);
239
240                 using (var writer = new StreamWriter(fileName))
241                 {
242                     writer.WriteLine("**** TraceOut: {0} ****", DateTime.Now.ToString());
243                     writer.WriteLine(Properties.Resources.TraceOutText1, ApplicationSettings.FeedbackEmailAddress);
244                     writer.WriteLine(Properties.Resources.TraceOutText2, ApplicationSettings.FeedbackTwitterName);
245                     writer.WriteLine();
246                     writer.WriteLine(Properties.Resources.TraceOutText3);
247                     writer.WriteLine(Properties.Resources.TraceOutText4, Environment.OSVersion.VersionString);
248                     writer.WriteLine(Properties.Resources.TraceOutText5, Environment.Version.ToString());
249                     writer.WriteLine(Properties.Resources.TraceOutText6, MyCommon.GetAssemblyName(), fileVersion);
250                     writer.WriteLine(Message);
251                     writer.WriteLine();
252                 }
253             }
254         }
255
256         // エラー内容をバッファに書き出し
257         // 注意:最終的にファイル出力されるエラーログに記録されるため次の情報は書き出さない
258         // 文頭メッセージ、権限、動作環境
259         // Dataプロパティにある終了許可フラグのパースもここで行う
260
261         public static string ExceptionOutMessage(Exception ex)
262         {
263             bool IsTerminatePermission = true;
264             return ExceptionOutMessage(ex, ref IsTerminatePermission);
265         }
266
267         public static string ExceptionOutMessage(Exception ex, ref bool IsTerminatePermission)
268         {
269             if (ex == null) return "";
270
271             var buf = new StringBuilder();
272
273             buf.AppendFormat(Properties.Resources.UnhandledExceptionText8, ex.GetType().FullName, ex.Message);
274             buf.AppendLine();
275             if (ex.Data != null)
276             {
277                 var needHeader = true;
278                 foreach (DictionaryEntry dt in ex.Data)
279                 {
280                     if (needHeader)
281                     {
282                         buf.AppendLine();
283                         buf.AppendLine("-------Extra Information-------");
284                         needHeader = false;
285                     }
286                     buf.AppendFormat("{0}  :  {1}", dt.Key, dt.Value);
287                     buf.AppendLine();
288                     if (dt.Key.Equals("IsTerminatePermission"))
289                     {
290                         IsTerminatePermission = (bool)dt.Value;
291                     }
292                 }
293                 if (!needHeader)
294                 {
295                     buf.AppendLine("-----End Extra Information-----");
296                 }
297             }
298             buf.AppendLine(ex.StackTrace);
299             buf.AppendLine();
300
301             //InnerExceptionが存在する場合書き出す
302             var _ex = ex.InnerException;
303             var nesting = 0;
304             while (_ex != null)
305             {
306                 buf.AppendFormat("-----InnerException[{0}]-----\r\n", nesting);
307                 buf.AppendLine();
308                 buf.AppendFormat(Properties.Resources.UnhandledExceptionText8, _ex.GetType().FullName, _ex.Message);
309                 buf.AppendLine();
310                 if (_ex.Data != null)
311                 {
312                     var needHeader = true;
313
314                     foreach (DictionaryEntry dt in _ex.Data)
315                     {
316                         if (needHeader)
317                         {
318                             buf.AppendLine();
319                             buf.AppendLine("-------Extra Information-------");
320                             needHeader = false;
321                         }
322                         buf.AppendFormat("{0}  :  {1}", dt.Key, dt.Value);
323                         if (dt.Key.Equals("IsTerminatePermission"))
324                         {
325                             IsTerminatePermission = (bool)dt.Value;
326                         }
327                     }
328                     if (!needHeader)
329                     {
330                         buf.AppendLine("-----End Extra Information-----");
331                     }
332                 }
333                 buf.AppendLine(_ex.StackTrace);
334                 buf.AppendLine();
335                 nesting++;
336                 _ex = _ex.InnerException;
337             }
338             return buf.ToString();
339         }
340
341         public static bool ExceptionOut(Exception ex)
342         {
343             lock (LockObj)
344             {
345                 var IsTerminatePermission = true;
346                 var now = DateTime.Now;
347                 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);
348
349                 using (var writer = new StreamWriter(fileName))
350                 {
351                     var ident = WindowsIdentity.GetCurrent();
352                     var princ = new WindowsPrincipal(ident);
353
354                     writer.WriteLine(Properties.Resources.UnhandledExceptionText1, DateTime.Now.ToString());
355                     writer.WriteLine(Properties.Resources.UnhandledExceptionText2, ApplicationSettings.FeedbackEmailAddress);
356                     writer.WriteLine(Properties.Resources.UnhandledExceptionText3, ApplicationSettings.FeedbackTwitterName);
357                     // 権限書き出し
358                     writer.WriteLine(Properties.Resources.UnhandledExceptionText11 + princ.IsInRole(WindowsBuiltInRole.Administrator).ToString());
359                     writer.WriteLine(Properties.Resources.UnhandledExceptionText12 + princ.IsInRole(WindowsBuiltInRole.User).ToString());
360                     writer.WriteLine();
361                     // OSVersion,AppVersion書き出し
362                     writer.WriteLine(Properties.Resources.UnhandledExceptionText4);
363                     writer.WriteLine(Properties.Resources.UnhandledExceptionText5, Environment.OSVersion.VersionString);
364                     writer.WriteLine(Properties.Resources.UnhandledExceptionText6, Environment.Version.ToString());
365                     writer.WriteLine(Properties.Resources.UnhandledExceptionText7, MyCommon.GetAssemblyName(), fileVersion);
366
367                     writer.Write(ExceptionOutMessage(ex, ref IsTerminatePermission));
368                     writer.Flush();
369                 }
370
371                 switch (MessageBox.Show(MyCommon.ReplaceAppName(string.Format(Properties.Resources.UnhandledExceptionText9, fileName, ApplicationSettings.FeedbackEmailAddress, ApplicationSettings.FeedbackTwitterName, Environment.NewLine)),
372                                    Properties.Resources.UnhandledExceptionText10, MessageBoxButtons.YesNoCancel, MessageBoxIcon.Error))
373                 {
374                     case DialogResult.Yes:
375                         Process.Start(fileName);
376                         return false;
377                     case DialogResult.No:
378                         return false;
379                     case DialogResult.Cancel:
380                         return IsTerminatePermission;
381                     default:
382                         throw new Exception("");
383                 }
384             }
385         }
386
387         /// <summary>
388         /// URLに含まれているマルチバイト文字列を%xx形式でエンコードします。
389         /// <newpara>
390         /// マルチバイト文字のコードはUTF-8またはUnicodeで自動的に判断します。
391         /// </newpara>
392         /// </summary>
393         /// <param name = input>エンコード対象のURL</param>
394         /// <returns>マルチバイト文字の部分をUTF-8/%xx形式でエンコードした文字列を返します。</returns>
395
396         public static string urlEncodeMultibyteChar(string _input)
397         {
398             Uri uri = null;
399             var sb = new StringBuilder(256);
400             var result = "";
401             var c_ = 'd';
402             foreach (var c in _input)
403             {
404                 c_ = c;
405                 if (Convert.ToInt32(c) > 127) break;
406             }
407             if (Convert.ToInt32(c_) <= 127) return _input;
408
409             var input = HttpUtility.UrlDecode(_input);
410         retry:
411             foreach (char c in input)
412             {
413                 if (Convert.ToInt32(c) > 255)
414                 {
415                     // Unicodeの場合(1charが複数のバイトで構成されている)
416                     // Uriクラスをnewして再構成し、入力をPathAndQueryのみとしてやり直す
417                     foreach (var b in Encoding.UTF8.GetBytes(c.ToString()))
418                     {
419                         sb.AppendFormat("%{0:X2}", b);
420                     }
421                 }
422                 else if (Convert.ToInt32(c) > 127 || c == '%')
423                 {
424                     // UTF-8の場合
425                     // Uriクラスをnewして再構成し、入力をinputからAuthority部分を除去してやり直す
426                     if (uri == null)
427                     {
428                         uri = new Uri(input);
429                         input = input.Remove(0, uri.GetLeftPart(UriPartial.Authority).Length);
430                         sb.Length = 0;
431                         goto retry;
432                     }
433                     else
434                     {
435                         sb.Append("%" + Convert.ToInt16(c).ToString("X2").ToUpper());
436                     }
437                 }
438                 else
439                 {
440                     sb.Append(c);
441                 }
442             }
443
444             if (uri == null)
445             {
446                 result = sb.ToString();
447             }
448             else
449             {
450                 result = uri.GetLeftPart(UriPartial.Authority) + sb.ToString();
451             }
452
453             return result;
454         }
455
456         ////// <summary>
457         ////// URLのドメイン名をPunycode展開します。
458         ////// <para>
459         ////// ドメイン名がIDNでない場合はそのまま返します。
460         ////// ドメインラベルの区切り文字はFULLSTOP(.、U002E)に置き換えられます。
461         ////// </para>
462         ////// </summary>
463         ////// <param name="input">展開対象のURL</param>
464         ////// <returns>IDNが含まれていた場合はPunycodeに展開したURLをを返します。Punycode展開時にエラーが発生した場合はnullを返します。</returns>
465
466         public static string IDNDecode(string input)
467         {
468             var IDNConverter = new IdnMapping();
469
470             if (!input.Contains("://")) return null;
471
472             // ドメイン名をPunycode展開
473             string Domain;
474             string AsciiDomain;
475
476             try
477             {
478                 Domain = input.Split('/')[2];
479                 AsciiDomain = IDNConverter.GetAscii(Domain);
480             }
481             catch (Exception)
482             {
483                 return null;
484             }
485
486             return input.Replace("://" + Domain, "://" + AsciiDomain);
487         }
488
489         public static void MoveArrayItem(int[] values, int idx_fr, int idx_to)
490         {
491             var moved_value = values[idx_fr];
492             var num_moved = Math.Abs(idx_fr - idx_to);
493
494             if (idx_to < idx_fr)
495             {
496                 Array.Copy(values, idx_to, values,
497                     idx_to + 1, num_moved);
498             }
499             else
500             {
501                 Array.Copy(values, idx_fr + 1, values,
502                     idx_fr, num_moved);
503             }
504
505             values[idx_to] = moved_value;
506         }
507
508         public static string EncryptString(string str)
509         {
510             if (string.IsNullOrEmpty(str)) return "";
511
512             //文字列をバイト型配列にする
513             var bytesIn = Encoding.UTF8.GetBytes(str);
514
515             //DESCryptoServiceProviderオブジェクトの作成
516             using (var des = new DESCryptoServiceProvider())
517             {
518                 //共有キーと初期化ベクタを決定
519                 //パスワードをバイト配列にする
520                 var bytesKey = Encoding.UTF8.GetBytes("_tween_encrypt_key_");
521                 //共有キーと初期化ベクタを設定
522                 des.Key = ResizeBytesArray(bytesKey, des.Key.Length);
523                 des.IV = ResizeBytesArray(bytesKey, des.IV.Length);
524
525                 MemoryStream msOut = null;
526                 ICryptoTransform desdecrypt = null;
527
528                 try
529                 {
530                     //暗号化されたデータを書き出すためのMemoryStream
531                     msOut = new MemoryStream();
532
533                     //DES暗号化オブジェクトの作成
534                     desdecrypt = des.CreateEncryptor();
535
536                     //書き込むためのCryptoStreamの作成
537                     using (CryptoStream cryptStream = new CryptoStream(msOut, desdecrypt, CryptoStreamMode.Write))
538                     {
539                         //Disposeが重複して呼ばれないようにする
540                         MemoryStream msTmp = msOut;
541                         msOut = null;
542                         desdecrypt = null;
543
544                         //書き込む
545                         cryptStream.Write(bytesIn, 0, bytesIn.Length);
546                         cryptStream.FlushFinalBlock();
547                         //暗号化されたデータを取得
548                         var bytesOut = msTmp.ToArray();
549
550                         //Base64で文字列に変更して結果を返す
551                         return Convert.ToBase64String(bytesOut);
552                     }
553                 }
554                 finally
555                 {
556                     if (msOut != null) msOut.Dispose();
557                     if (desdecrypt != null) desdecrypt.Dispose();
558                 }
559             }
560         }
561
562         public static string DecryptString(string str)
563         {
564             if (string.IsNullOrEmpty(str)) return "";
565
566             //DESCryptoServiceProviderオブジェクトの作成
567             using (var des = new System.Security.Cryptography.DESCryptoServiceProvider())
568             {
569                 //共有キーと初期化ベクタを決定
570                 //パスワードをバイト配列にする
571                 var bytesKey = Encoding.UTF8.GetBytes("_tween_encrypt_key_");
572                 //共有キーと初期化ベクタを設定
573                 des.Key = ResizeBytesArray(bytesKey, des.Key.Length);
574                 des.IV = ResizeBytesArray(bytesKey, des.IV.Length);
575
576                 //Base64で文字列をバイト配列に戻す
577                 var bytesIn = Convert.FromBase64String(str);
578
579                 MemoryStream msIn = null;
580                 ICryptoTransform desdecrypt = null;
581                 CryptoStream cryptStreem = null;
582
583                 try
584                 {
585                     //暗号化されたデータを読み込むためのMemoryStream
586                     msIn = new MemoryStream(bytesIn);
587                     //DES復号化オブジェクトの作成
588                     desdecrypt = des.CreateDecryptor();
589                     //読み込むためのCryptoStreamの作成
590                     cryptStreem = new CryptoStream(msIn, desdecrypt, CryptoStreamMode.Read);
591
592                     //Disposeが重複して呼ばれないようにする
593                     msIn = null;
594                     desdecrypt = null;
595
596                     //復号化されたデータを取得するためのStreamReader
597                     using (StreamReader srOut = new StreamReader(cryptStreem, Encoding.UTF8))
598                     {
599                         //Disposeが重複して呼ばれないようにする
600                         cryptStreem = null;
601
602                         //復号化されたデータを取得する
603                         var result = srOut.ReadToEnd();
604
605                         return result;
606                     }
607                 }
608                 finally
609                 {
610                     if (msIn != null) msIn.Dispose();
611                     if (desdecrypt != null) desdecrypt.Dispose();
612                     if (cryptStreem != null) cryptStreem.Dispose();
613                 }
614             }
615         }
616
617         public static byte[] ResizeBytesArray(byte[] bytes,
618                                     int newSize)
619         {
620             var newBytes = new byte[newSize];
621             if (bytes.Length <= newSize)
622             {
623                 foreach (var i in Enumerable.Range(0, bytes.Length))
624                 {
625                     newBytes[i] = bytes[i];
626                 }
627             }
628             else
629             {
630                 var pos = 0;
631                 foreach (var i in Enumerable.Range(0, bytes.Length))
632                 {
633                     newBytes[pos] = unchecked((byte)(newBytes[pos] ^ bytes[i]));
634                     pos++;
635                     if (pos >= newBytes.Length)
636                     {
637                         pos = 0;
638                     }
639                 }
640             }
641             return newBytes;
642         }
643
644         public static bool IsNT6()
645         {
646             //NT6 kernelかどうか検査
647             return Environment.OSVersion.Platform == PlatformID.Win32NT && Environment.OSVersion.Version.Major == 6;
648         }
649
650         [FlagsAttribute()]
651         public enum TabUsageType
652         {
653             Undefined = 0,
654             Home = 1,      //Unique
655             Mentions = 2,     //Unique
656             DirectMessage = 4,   //Unique
657             Favorites = 8,       //Unique
658             UserDefined = 16,
659             LocalQuery = 32,      //Pin(no save/no save query/distribute/no update(normal update))
660             Profile = 64,         //Pin(save/no distribute/manual update)
661             PublicSearch = 128,    //Pin(save/no distribute/auto update)
662             Lists = 256,
663             Related = 512,
664             UserTimeline = 1024,
665             //RTMyTweet
666             //RTByOthers
667             //RTByMe
668         }
669
670         public static string fileVersion = "";
671
672         public static string GetUserAgentString()
673         {
674             if (string.IsNullOrEmpty(fileVersion))
675             {
676                 throw new Exception("fileversion is not Initialized.");
677             }
678             return GetAssemblyName() + "/" + fileVersion;
679         }
680
681         public static ApiInformation TwitterApiInfo = new ApiInformation();
682
683         public static bool IsAnimatedGif(string filename)
684         {
685             Image img = null;
686             try
687             {
688                 img = Image.FromFile(filename);
689                 if (img == null) return false;
690                 if (img.RawFormat.Guid == ImageFormat.Gif.Guid)
691                 {
692                     var fd = new FrameDimension(img.FrameDimensionsList[0]);
693                     var fd_count = img.GetFrameCount(fd);
694                     if (fd_count > 1)
695                     {
696                         return true;
697                     }
698                     else
699                     {
700                         return false;
701                     }
702                 }
703                 return false;
704             }
705             catch (Exception)
706             {
707                 return false;
708             }
709             finally
710             {
711                 if (img != null) img.Dispose();
712             }
713         }
714
715         public static DateTime DateTimeParse(string input)
716         {
717             DateTime rslt;
718             string[] format = {
719                 "ddd MMM dd HH:mm:ss zzzz yyyy",
720                 "ddd, d MMM yyyy HH:mm:ss zzzz",
721             };
722             foreach (var fmt in format)
723             {
724                 if (DateTime.TryParseExact(input,
725                                           fmt,
726                                           DateTimeFormatInfo.InvariantInfo,
727                                           DateTimeStyles.None,
728                                           out rslt))
729                 {
730                     return rslt;
731                 }
732                 else
733                 {
734                     continue;
735                 }
736             }
737             TraceOut("Parse Error(DateTimeFormat) : " + input);
738             return new DateTime();
739         }
740
741         public static T CreateDataFromJson<T>(string content)
742         {
743             T data;
744             using (var stream = new MemoryStream())
745             {
746                 var buf = Encoding.Unicode.GetBytes(content);
747                 stream.Write(Encoding.Unicode.GetBytes(content), offset: 0, count: buf.Length);
748                 stream.Seek(offset: 0, loc: SeekOrigin.Begin);
749                 data = (T)((new DataContractJsonSerializer(typeof(T))).ReadObject(stream));
750             }
751             return data;
752         }
753
754         public static bool IsNetworkAvailable()
755         {
756             try
757             {
758                 return NetworkInterface.GetIsNetworkAvailable();
759             }
760             catch(Exception)
761             {
762                 return false;
763             }
764         }
765
766         static bool IsValidEmail(string strIn)
767         {
768             // Return true if strIn is in valid e-mail format.
769             return Regex.IsMatch(strIn,
770                    @"^(?("")("".+?""@)|(([0-9a-zA-Z]((\.(?!\.))|[-!#\$%&'\*\+/=\?\^`\{\}\|~\w])*)(?<=[0-9a-zA-Z])@))" +
771                    @"(?(\[)(\[(\d{1,3}\.){3}\d{1,3}\])|(([0-9a-zA-Z][-\w]*[0-9a-zA-Z]\.)+[a-zA-Z]{2,6}))$");
772         }
773
774         /// <summary>
775         /// 指定された修飾キーが押されている状態かを取得します。
776         /// </summary>
777         /// <param name="keys">状態を調べるキー</param>
778         /// <returns><paramref name="keys"/> で指定された修飾キーがすべて押されている状態であれば true。それ以外であれば false。</returns>
779         public static bool IsKeyDown(params Keys[] keys)
780         {
781             foreach (Keys key in keys)
782             {
783                 if ((Control.ModifierKeys & key) != key)
784                 {
785                     return false;
786                 }
787             }
788             return true;
789         }
790
791         /// <summary>
792         /// アプリケーションのアセンブリ名を取得します。
793         /// </summary>
794         /// <remarks>
795         /// VB.NETの<code>My.Application.Info.AssemblyName</code>と(ほぼ)同じ動作をします。
796         /// </remarks>
797         /// <returns>アプリケーションのアセンブリ名</returns>
798         public static string GetAssemblyName()
799         {
800             return Assembly.GetEntryAssembly().GetName().Name;
801         }
802
803         /// <summary>
804         /// 文字列中に含まれる %AppName% をアプリケーション名に置換する
805         /// </summary>
806         /// <param name="orig">対象となる文字列</param>
807         /// <returns>置換後の文字列</returns>
808         public static string ReplaceAppName(string orig)
809         {
810             return orig.Replace("%AppName%", Application.ProductName);
811         }
812
813         /// <summary>
814         /// 表示用のバージョン番号の文字列を生成する
815         /// </summary>
816         /// <remarks>
817         /// バージョン1.0.0.1のように末尾が0でない(=開発版)の場合は「1.0.1-beta1」が出力される
818         /// </remarks>
819         /// <returns>
820         /// 生成されたバージョン番号の文字列
821         /// </returns>
822         public static string GetReadableVersion(string fileVersion = null)
823         {
824             if (fileVersion == null)
825             {
826                 fileVersion = MyCommon.fileVersion;
827             }
828
829             if (string.IsNullOrEmpty(fileVersion))
830             {
831                 return null;
832             }
833
834             int[] version = fileVersion.Split('.')
835                 .Select(x => int.Parse(x)).ToArray();
836
837             if (version[3] == 0)
838             {
839                 return string.Format("{0}.{1}.{2}", version[0], version[1], version[2]);
840             }
841             else
842             {
843                 version[2] = version[2] + 1;
844
845                 // 10を越えたら桁上げ
846                 if (version[2] > 10)
847                 {
848                     version[1] += version[2] / 10;
849                     version[2] %= 10;
850
851                     if (version[1] > 10)
852                     {
853                         version[0] += version[1] / 10;
854                         version[1] %= 10;
855                     }
856                 }
857
858                 return string.Format("{0}.{1}.{2}-beta{3}", version[0], version[1], version[2], version[3]);
859             }
860         }
861
862         public const string TwitterUrl = "https://twitter.com/";
863
864         public static string GetStatusUrl(PostClass post)
865         {
866             if (post.RetweetedId == 0)
867                 return GetStatusUrl(post.ScreenName, post.StatusId);
868             else
869                 return GetStatusUrl(post.ScreenName, post.RetweetedId);
870         }
871
872         public static string GetStatusUrl(string screenName, long statusId)
873         {
874             return TwitterUrl + screenName + "/status/" + statusId.ToString();
875         }
876     }
877 }