OSDN Git Service

ブロックの括弧を独立した行に書く (SA1500, SA1501, SA1502)
[opentween/open-tween.git] / OpenTween / Setting / SettingBase.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      kim_upsilon (@kim_upsilon) <https://upsilo.net/~upsilon/>
8 // All rights reserved.
9 //
10 // This file is part of OpenTween.
11 //
12 // This program is free software; you can redistribute it and/or modify it
13 // under the terms of the GNU General Public License as published by the Free
14 // Software Foundation; either version 3 of the License, or (at your option)
15 // any later version.
16 //
17 // This program is distributed in the hope that it will be useful, but
18 // WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
19 // or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
20 // for more details.
21 //
22 // You should have received a copy of the GNU General Public License along
23 // with this program. If not, see <http://www.gnu.org/licenses/>, or write to
24 // the Free Software Foundation, Inc., 51 Franklin Street - Fifth Floor,
25 // Boston, MA 02110-1301, USA.
26
27 #nullable enable
28
29 using System;
30 using System.Collections.Generic;
31 using System.IO;
32 using System.Linq;
33 using System.Text;
34 using System.Threading;
35 using System.Windows.Forms;
36 using System.Xml;
37 using System.Xml.Serialization;
38
39 namespace OpenTween
40 {
41     public abstract class SettingBase<T>
42         where T : class, new()
43     {
44         /// <summary>
45         /// XML に含まれる追加データを保持するフィールド
46         /// </summary>
47         /// <remarks>
48         /// 他バージョンから設定をコピーした場合など、クラスに存在しないフィールドが
49         /// XML に含まれていた場合に破棄せず保持するため必要となる。
50         /// </remarks>
51         [XmlAnyElement]
52         public XmlElement[] ExtraElements = Array.Empty<XmlElement>();
53
54         private static readonly object LockObj = new object();
55
56         protected static T LoadSettings(string fileId)
57         {
58             try
59             {
60                 var settingFilePath = GetSettingFilePath(fileId);
61                 if (!File.Exists(settingFilePath))
62                 {
63                     return new T();
64                 }
65
66                 lock (LockObj)
67                 {
68                     using var fs = new FileStream(settingFilePath, FileMode.Open, FileAccess.Read);
69                     fs.Position = 0;
70                     var xs = new XmlSerializer(typeof(T));
71                     var instance = (T)xs.Deserialize(fs);
72                     return instance;
73                 }
74             }
75             catch (FileNotFoundException)
76             {
77                 return new T();
78             }
79             catch (Exception)
80             {
81                 var backupFile = Path.Combine(
82                         Path.Combine(
83                             Application.StartupPath,
84                             ApplicationSettings.AssemblyName + "Backup1st"),
85                         typeof(T).Name + fileId + ".xml");
86                 if (File.Exists(backupFile))
87                 {
88                     try
89                     {
90                         lock (LockObj)
91                         {
92                             using var fs = new FileStream(backupFile, FileMode.Open, FileAccess.Read);
93                             fs.Position = 0;
94                             var xs = new XmlSerializer(typeof(T));
95                             var instance = (T)xs.Deserialize(fs);
96                             MessageBox.Show("File: " + GetSettingFilePath(fileId) + Environment.NewLine + "Use old setting file, because application can't read this setting file.");
97                             return instance;
98                         }
99                     }
100                     catch (Exception)
101                     {
102                     }
103                 }
104                 MessageBox.Show("File: " + GetSettingFilePath(fileId) + Environment.NewLine + "Use default setting, because application can't read this setting file.");
105                 return new T();
106             }
107         }
108
109         protected static T LoadSettings()
110             => LoadSettings("");
111
112         protected static void SaveSettings(T instance, string fileId)
113         {
114             const int SaveRetryMax = 3;
115
116             if (instance == null)
117                 return;
118
119             var retryCount = 0;
120             Exception? lastException = null;
121
122             var filePath = GetSettingFilePath(fileId);
123             do
124             {
125                 var tmpfilePath = GetSettingFilePath("_" + Path.GetRandomFileName());
126                 try
127                 {
128                     lock (LockObj)
129                     {
130                         using (var stream = new FileStream(tmpfilePath, FileMode.Create, FileAccess.Write))
131                         {
132                             var serializer = new XmlSerializer(typeof(T));
133                             serializer.Serialize(stream, instance);
134                             stream.Flush();
135                         }
136
137                         var fileInfo = new FileInfo(tmpfilePath);
138                         if (fileInfo.Length != 0)
139                         {
140                             // 成功
141                             File.Copy(tmpfilePath, filePath, true);
142                             return;
143                         }
144                     }
145                 }
146                 catch (Exception e)
147                 {
148                     lastException = e;
149                 }
150                 finally
151                 {
152                     try
153                     {
154                         if (File.Exists(tmpfilePath))
155                             File.Delete(tmpfilePath);
156                     }
157                     catch (Exception)
158                     {
159                     }
160                 }
161
162                 // リトライ
163                 retryCount++;
164                 Thread.Sleep(1000);
165
166             }
167             while (retryCount <= SaveRetryMax);
168
169             // リトライオーバー
170             if (lastException != null)
171                 MyCommon.ExceptionOut(lastException);
172
173             MessageBox.Show("Can't write setting XML.(" + filePath + ")", "Save Settings", MessageBoxButtons.OK);
174         }
175
176         protected static void SaveSettings(T instance)
177             => SaveSettings(instance, "");
178
179         public static string GetSettingFilePath(string fileId)
180             => Path.Combine(MyCommon.SettingPath, typeof(T).Name + fileId + ".xml");
181     }
182 }