Settings.java
     1: //========================================================================================
     2: //  Settings.java
     3: //    en:Settings
     4: //    ja:設定
     5: //  Copyright (C) 2003-2017 Makoto Kamada
     6: //
     7: //  This file is part of the XEiJ (X68000 Emulator in Java).
     8: //  You can use, modify and redistribute the XEiJ if the conditions are met.
     9: //  Read the XEiJ License for more details.
    10: //  http://stdkmd.com/xeij/
    11: //========================================================================================
    12: 
    13: //----------------------------------------------------------------------------------------
    14: //  設定ファイル
    15: //      +-----------------+
    16: //      | キー1=値1       |現在の設定sgsCurrentMap
    17: //      |      :          |
    18: //      | キーn=値n       |
    19: //      |                 |
    20: //      | _=設定A         |設定名="設定A"の設定
    21: //      | キーA1=値A1     |
    22: //      |       :         |
    23: //      | キーAn=値An     |
    24: //      |                 |
    25: //      | _=設定B         |設定名="設定B"の設定
    26: //      | キーB1=値B1     |
    27: //      |       :         |
    28: //      | キーBn=値Bn     |
    29: //      +-----------------+
    30: //    設定を設定名の昇順に列挙したテキストファイル
    31: //    設定毎の設定名はキー"_"の値に格納されている
    32: //    現在の設定sgsCurrentMapは設定名が""なので必ず先頭に来る
    33: //    設定毎にキーを昇順にソートしてから出力する
    34: //    設定名以外のキーはすべて英小文字で始まるので設定名のキー"_"の行が必ず先頭に来る
    35: //    現在の設定sgsCurrentMapの設定名のキー"_"の行は出力しない
    36: //    開始時の設定sgsStartMapと同じ値を持つキーは出力しない
    37: //
    38: //  現在の設定
    39: //    sgsCurrentMap
    40: //    現在の設定sgsCurrentMapは動的に更新できるが、通常は負荷を考慮して設定を保存するときにまとめて更新する
    41: //    現在の設定sgsCurrentMapの設定名は""。すなわち、現在の設定sgsCurrentMapのキー"_"の値は""
    42: //    すべての設定sgsRootMapのキー""の値が現在の設定sgsCurrentMap
    43: //
    44: //  設定ファイルを読み込む
    45: //    設定ファイルを読み込んですべての設定sgsRootMapに格納する
    46: //      開始時の設定sgsStartMapと同じ値を持つキーは保存されていないので、
    47: //      個々の設定は開始時の設定sgsStartMapを複製してから(キー"_"の値は"")、設定ファイルの内容を上書きする形で構築する
    48: //      設定ファイルの先頭は現在の設定sgsCurrentMap。設定名は""
    49: //    コマンドラインなどのパラメータのマップを作る。キー"config"が含まれる場合がある
    50: //    パラメータのマップにキー"config"があるとき
    51: //      パラメータのマップのキー"config"の値を復元する設定の設定名とする
    52: //      復元する設定があるとき
    53: //        復元する設定をコピーして現在の設定sgsCurrentMapとする(キー"_"の値は"")
    54: //      コマンドラインなどのパラメータのマップからキー"config"を取り除く
    55: //    現在の設定sgsCurrentMapにコマンドラインなどのパラメータのマップを上書きする
    56: //
    57: //  設定ファイルを保存する
    58: //    sgsRootMapをテキストに変換して設定ファイルに保存する
    59: //      開始時の設定sgsStartMapと同じ値を持つキーは出力しない
    60: //      現在の設定sgsCurrentMapのキー"_"は出力しない
    61: //
    62: //  「設定を保存」 Save Settings
    63: //    設定ファイルを保存する
    64: //
    65: //  「設定に名前を付けて保存」 Save Settings As
    66: //    新しい設定の設定名が""のときは何もしない
    67: //    すべての設定sgsRootMapに新しい設定があるときは上書きしてよいか確認する
    68: //    現在の設定をコピーして新しい設定を作る
    69: //    新しい設定のキー"_"の値を新しい設定の設定名にする
    70: //    すべての設定sgsRootMapに新しい設定の設定名をキー、新しい設定を値として加える
    71: //    設定ファイルを保存する
    72: //
    73: //  「名前を付けた設定を削除」 Remove Named Settings
    74: //    削除する設定の設定名が""のときは何もしない
    75: //    すべての設定sgsRootMapに削除する設定があるときは削除してよいか確認する
    76: //    すべての設定sgsRootMapから削除する設定の設定名のキーを取り除く
    77: //    設定ファイルを保存する
    78: //
    79: //  「設定を選択して再スタート」 Choice Settings and Restart
    80: //! 未対応
    81: //----------------------------------------------------------------------------------------
    82: 
    83: package xeij;
    84: 
    85: import java.awt.*;  //BasicStroke,BorderLayout,BoxLayout,Color,Component,Container,Cursor,Desktop,Dimension,Font,Frame,Graphics,Graphics2D,GraphicsDevice,GraphicsEnvironment,GridLayout,Image,Insets,Paint,Point,Rectangle,RenderingHints,Robot,Shape,Stroke,TexturePaint,Toolkit
    86: import java.awt.event.*;  //ActionEvent,ActionListener,ComponentAdapter,ComponentEvent,ComponentListener,FocusAdapter,FocusEvent,FocusListener,InputEvent,KeyAdapter,KeyEvent,KeyListener,MouseAdapter,MouseEvent,MouseListener,MouseMotionAdapter,MouseWheelEvent,WindowAdapter,WindowEvent,WindowListener,WindowStateListener
    87: import java.io.*;  //BufferedInputStream,BufferedOutputStream,BufferedReader,BufferedWriter,File,FileInputStream,FileNotFoundException,FileReader,InputStream,InputStreamReader,IOException,OutputStreamWriter,RandomAccessFile
    88: import java.lang.*;  //Boolean,Character,Class,Comparable,Double,Exception,Float,IllegalArgumentException,Integer,Long,Math,Number,Object,Runnable,SecurityException,String,StringBuilder,System
    89: import java.net.*;  //MalformedURLException,URI,URL
    90: import java.util.*;  //ArrayList,Arrays,Calendar,GregorianCalendar,HashMap,Map,Map.Entry,Timer,TimerTask,TreeMap
    91: import java.util.regex.*;  //Matcher,Pattern
    92: import javax.jnlp.*;  //BasicService,PersistenceService,ServiceManager,UnavailableServiceException
    93: import javax.swing.*;  //AbstractSpinnerModel,Box,ButtonGroup,DefaultListModel,ImageIcon,JApplet,JButton,JCheckBox,JCheckBoxMenuItem,JDialog,JFileChooser,JFrame,JLabel,JList,JMenu,JMenuBar,JMenuItem,JPanel,JRadioButton,JScrollPane,JSpinner,JTextArea,JTextField,JTextPane,JViewport,ScrollPaneConstants,SpinnerListModel,SpinnerNumberModel,SwingConstants,SwingUtilities,UIManager,UIDefaults,UnsupportedLookAndFeelException
    94: import javax.swing.event.*;  //CaretListener,ChangeEvent,ChangeListener,DocumentEvent,DocumentListener,ListSelectionListener
    95: import netscape.javascript.*;  //JSException,JSObject。jfxrt.jarではなくplugin.jarを使うこと
    96: 
    97: public class Settings {
    98: 
    99:   public static final boolean SGS_NAMED_SETTINGS = false;  //true=ローカルのとき設定に名前を付けられる。メニューで名前を指定して再起動することができないとあまり役に立たない
   100: 
   101:   //RestorableFrameのキーの一覧
   102:   //  ウインドウの位置とサイズ(~rect)、状態(~stat)、開くかどうか(~open)のパラメータで使う
   103:   public static final String SGS_ACM_FRAME_KEY = "acm";  //ACM アドレス変換キャッシュモニタ
   104:   public static final String SGS_ATW_FRAME_KEY = "atw";  //ATW 論理空間モニタ
   105:   public static final String SGS_BLG_FRAME_KEY = "blg";  //BLG 分岐ログ
   106:   public static final String SGS_DBP_FRAME_KEY = "dbp";  //DBP データブレークポイント
   107:   public static final String SGS_DDP_FRAME_KEY = "ddp";  //DDP 逆アセンブルリスト
   108:   public static final String SGS_DGT_FRAME_KEY = "dgt";  //DGT コンソールウインドウ
   109:   public static final String SGS_DMP_FRAME_KEY = "dmp";  //DMP メモリダンプリスト
   110:   public static final String SGS_DRP_FRAME_KEY = "drp";  //DRP レジスタ
   111:   public static final String SGS_FNT_FRAME_KEY = "fnt";  //FNT フォントエディタ
   112:   public static final String SGS_FRM_FRAME_KEY = "frm";  //FRM メインウインドウ
   113:   public static final String SGS_GRS_FRAME_KEY = "grs";
   114:   public static final String SGS_GSA_FRAME_KEY = "gsa";
   115:   public static final String SGS_PAA_FRAME_KEY = "paa";  //PAA 物理空間モニタ
   116:   public static final String SGS_PFF_FRAME_KEY = "pff";  //PFF プロファイリング
   117:   public static final String SGS_PFV_FRAME_KEY = "pfv";  //PFV プログラムフロービジュアライザ
   118:   public static final String SGS_PPI_FRAME_KEY = "ppi";  //PPI ジョイスティック
   119:   public static final String SGS_PRN_FRAME_KEY = "prn";  //PRN プリンタ
   120:   public static final String SGS_RBP_FRAME_KEY = "rbp";  //RBP ラスタブレークポイント
   121:   public static final String SGS_RTL_FRAME_KEY = "rtl";  //RTL ルートポインタリスト
   122:   public static final String SGS_SMN_FRAME_KEY = "smn";  //SMN 音声モニタ
   123:   public static final String SGS_SMT_FRAME_KEY = "smt";  //SMT 表示モードテスト
   124:   public static final String SGS_SPV_FRAME_KEY = "spv";  //SPV スプライトパターンビュア
   125:   public static final String SGS_TRM_FRAME_KEY = "trm";  //TRM ターミナル
   126:   public static final String[] SGS_FRAME_KEYS = {
   127:     SGS_ACM_FRAME_KEY,
   128:     SGS_ATW_FRAME_KEY,
   129:     SGS_BLG_FRAME_KEY,
   130:     SGS_DBP_FRAME_KEY,
   131:     SGS_DDP_FRAME_KEY,
   132:     SGS_DGT_FRAME_KEY,
   133:     SGS_DMP_FRAME_KEY,
   134:     SGS_DRP_FRAME_KEY,
   135:     SGS_FNT_FRAME_KEY,
   136:     SGS_FRM_FRAME_KEY,
   137:     SGS_GRS_FRAME_KEY,
   138:     SGS_GSA_FRAME_KEY,
   139:     SGS_PAA_FRAME_KEY,
   140:     SGS_PFF_FRAME_KEY,
   141:     SGS_PFV_FRAME_KEY,
   142:     SGS_PPI_FRAME_KEY,
   143:     SGS_PRN_FRAME_KEY,
   144:     SGS_RBP_FRAME_KEY,
   145:     SGS_RTL_FRAME_KEY,
   146:     SGS_SMN_FRAME_KEY,
   147:     SGS_SMT_FRAME_KEY,
   148:     SGS_SPV_FRAME_KEY,
   149:     SGS_TRM_FRAME_KEY,
   150:   };
   151: 
   152:   //デフォルトのパラメータ
   153:   //  指定できるパラメータのキーとデフォルトの値をすべて書く
   154:   //    例外
   155:   //      ウインドウの位置とサイズ(~bounds)と状態(~state)のパラメータはまとめて初期化するのでここには書かない
   156:   //      ローカルのときだけ指定できるベンチマークなどのオプションはsgsGetArgumentParameters()で処理するのでここには書かない
   157:   //      設定名のキー"_"は個別に格納するのでここには書かない
   158:   //        デフォルトの設定sgsDefaultMapと開始時の設定sgsStartMapにキー"_"は存在しない
   159:   //    例外を除いてここにないパラメータは指定しても無視される
   160:   //  キーはnullではない。値もnullではない
   161:   //  キーは""ではない。値が""のときは指定されていないものとみなす
   162:   //  設定名のキーは"_"。設定名以外のキーは英小文字で始まり、英小文字または数字のみから成る
   163:   //  デフォルトの値が"off"または"on"のパラメータの値は"off"または"on"に限られる
   164:   //    "0","no","off"を指定すると"off"、それ以外は"on"に読み替えられる
   165:   public static final String SGS_DEFAULT_PARAMETERS = (
   166:     //PRG
   167:     "verbose;on;" +  //冗長表示(on/off)
   168:     //SGS
   169:     //"_;;" +  //この設定の設定名。ここには書かない
   170:     "saveonexit;on;" +  //終了時に設定を保存(on/off)
   171:     "config;;" +  //復元する設定の設定名。パラメータで指定する。設定ファイルには出力しない
   172:     "lang;en;" +  //言語(en/ja)。初期値は動作環境の言語
   173:     "home;;" +  //ホームディレクトリ。初期値は動作環境のホームディレクトリ
   174:     "dir;;" +  //カレントディレクトリ。初期値は動作環境のカレントディレクトリ
   175:     //LNF
   176:     "hhssbb;667,667,700,300,0,1000;" +  //色
   177:     //KBD
   178:     "keyboard;standard;" +  //キーボードの種類(none,standard,compact)
   179:     //PNL
   180:     "fullscreen;off;" +  //全画面表示(on/off)
   181:     "fitinwindow;on;" +  //ウインドウに合わせる(on/off)
   182:     "fixedscale;100;" +  //固定サイズの倍率
   183:     "interpolation;bilinear;" +  //補間アルゴリズム(nearest,bilinear,bicubic)
   184:     //MUS
   185:     "seamless;on;" +  //シームレス/エクスクルーシブ(on/off)
   186:     "ctrlright;off;" +  //Ctrlキー+左ボタンを右ボタンとみなす(on/off)
   187:     "edgeaccel;off;" +  //縁部加速
   188:     "mousespeed;20;" +  //マウスカーソルの速度(0~40)
   189:     "hostspixelunits;off;" +  //ホストの画素単位で動く(on/off)
   190:     //MPU
   191:     "model;Hybrid;" +  //機種(EXPERT|SUPER|XVI|Compact|Hybrid|X68030|060turbo)
   192:     "mpu;;" +  //MPUの種類(0=MC68000/3=MC68EC030)
   193:     "clock;;" +  //MPUの動作周波数(1..1000/EXPERT=10/SUPER=10/XVI=16.7/Compact=25/Hybrid=33.3/X68030=25)
   194:     "mhz;100;" +  //任意の周波数(1~1000)。任意の負荷率がonのときの周波数のスピナーの値
   195:     "util;off;" +  //任意の負荷率(on/off)
   196:     "ratio;100;" +  //任意の負荷率(1~100)
   197:     //FPU
   198:     "fpumode;1;" +  //FPUモード(0=なし/1=拡張精度/2=三倍精度)
   199:     "fullspecfpu;off;" +  //フルスペックFPU(on/off)
   200:     //FPK
   201:     "fefunc;on;" +  //FEファンクション命令(on/off)
   202:     "rejectfloat;off;" +  //FLOATn.Xを組み込まない(on/off)
   203:     //BUS
   204:     "highmemory;0;" +  //X68030のハイメモリのサイズ(MB)(0/16)
   205:     "highmemorysave;off;" +  //X68030のハイメモリの内容を保存する(on/off)
   206:     "highmemorydata;;" +  //X68030のハイメモリの内容(gzip+base64)
   207:     "localmemory;128;" +  //060turboのローカルメモリのサイズ(MB)(0/16/32/64/128/256)
   208:     "localmemorysave;off;" +  //060turboのローカルメモリの内容を保存する(on/off)
   209:     "localmemorydata;;" +  //060turboのローカルメモリの内容(gzip+base64)
   210:     "cutfc2pin;off;" +  //FC2ピンをカットする(on/off)
   211:     //MMR
   212:     "memory;12;" +  //メインメモリのサイズ(1/2/4/6/8/10/12)
   213:     "memorysave;on;" +  //メインメモリの内容を保存する(on/off)
   214:     "memorydata;;" +  //メインメモリの内容(gzip+base64)
   215:     //CRT
   216:     "intermittent;0;" +  //間欠描画(0~4)
   217:     "extendedgraphics;off;" +  //拡張グラフィックス画面(on/off)
   218:     //SND
   219:     "sound;on;" +  //音声出力(on/off)
   220:     "volume;20;" +  //ボリューム(0~40)
   221:     "soundinterpolation;linear;" +  //音声補間(thinning/linear/constant-area/linear-area)
   222:     //OPM
   223:     "opmoutput;on;" +  //OPM出力
   224:     //PCM
   225:     "pcmoutput;on;" +  //PCM出力
   226:     "pcminterpolation;linear;" +  //PCM補間(constant/linear/hermite)
   227:     "pcmoscfreq;0;" +  //PCM原発振周波数(0=8MHz/4MHz,1=8MHz/16MHz)
   228:     //FDC
   229:     //  FDDのイメージファイル
   230:     "fd0;;fd1;;fd2;;fd3;;" +
   231:     //HDC
   232:     //  SASI HDDのイメージファイル
   233:     "hd0;;hd1;;hd2;;hd3;;hd4;;hd5;;hd6;;hd7;;hd8;;hd9;;hd10;;hd11;;hd12;;hd13;;hd14;;hd15;;" +
   234:     //SPC
   235:     //  SCSI HDDのイメージファイル
   236:     //    拡張  内蔵  sc[0-7]  sc[8-15]
   237:     //    -----------------------------
   238:     //    有効  有効    拡張     内蔵
   239:     //    有効  無効    拡張     無効
   240:     //    無効  有効    内蔵     無効
   241:     //    無効  無効    無効     無効
   242:     "sc0;;sc1;;sc2;;sc3;;sc4;;sc5;;sc6;;sc7;;sc8;;sc9;;sc10;;sc11;;sc12;;sc13;;sc14;;sc15;;" +  //SCSI
   243:     //PPI
   244:     "joykey;on;" +  //キーにボタンを割り当てる
   245:     "joyauto;on;" +  //自動有効化
   246:     "joyblock;on;" +  //変換されたキーを入力しない
   247:     "joymap;38,40,37,39,,90,88,,83,68;" +  //ジョイスティックのボタンを割り当てるキーと連射の設定
   248:     //HFS
   249:     //  ホストのディレクトリ名
   250:     //  hf0の初期値はカレントディレクトリ
   251:     "hf0;;hf1;;hf2;;hf3;;hf4;;hf5;;hf6;;hf7;;hf8;;hf9;;hf10;;hf11;;hf12;;hf13;;hf14;;hf15;;" +
   252:     //EXS
   253:     "scsiex;off;" +  //on=拡張SCSIポートを有効にする
   254:     "scsiexrom;;" +  //SCSIEXROMのイメージファイル(8KB)。SCSIEXROM.DAT
   255:     //SMR
   256:     "boot;;" +  //起動デバイス(std/fdN/hdN/scN/hfN/rom$X/ram$X)
   257:     "keydly;-1;" +  //リピートディレイ(-1=既定/200+100*n)
   258:     "keyrep;-1;" +  //リピートインターバル(-1=既定/30+5*n^2)
   259:     "sram;;" +  //SRAMイメージファイル名
   260:     "sramdata;;" +  //SRAMの内容(gzip+base64)
   261:     "sramsize;16;" +  //SRAMの容量(16/32/64)
   262:     //ROM
   263:     "rom;;" +  //"ROM.DAT,ROM.TMP" ROMのイメージファイル(1MB)。ROM.DAT
   264:     "iplrom;;" +  //IPLROMのイメージファイル(128KB)
   265:     "rom30;;" +  //X68030のROMの拡張部分のイメージファイル(128KB)。ROM30.DAT
   266:     "romdb;off;" +  //IPLでROMデバッガを強制的に起動する(on/off)
   267:     "scsiinrom;;" +  //SCSIINROMのイメージファイル(8KB)。SCSIINROM.DAT
   268:     //FNT
   269:     "cgrom;CGROM_XEiJ.DAT,CGROM.DAT;" +  //フォントファイル。CGROM_XEiJ.DATはMISAKI_G.F8,GOX80.F12,GOL80.FON,MIN.F24を組み合わせたもの
   270:     "omusubi;off;" +  //おむすびフォント
   271:     //PRN
   272:     "prnauto;off;" +  //on=プリンタ出力を自動保存する
   273:     "prnpath;printer;"  //プリンタ出力を保存するディレクトリ
   274:     );
   275: 
   276:   public static final String SGS_APPDATA_FOLDER = "XEiJ";  //Windowsのみ。AppData/Roamingフォルダに掘るフォルダの名前
   277:   public static final String SGS_INI = "XEiJ.ini";  //設定ファイル名
   278: 
   279:   public static final Pattern SGS_BOOT_DEVICE_PATTERN = Pattern.compile ("^(?:std|(?:fd|hd|sc|hf)\\d+|r[oa]m\\$[0-9A-Fa-f]+)$", Pattern.CASE_INSENSITIVE);  //-bootに指定できる起動デバイス名
   280: 
   281:   public static String sgsAppDataRoamingFolder;  //Windowsのみ。AppData/Roamingフォルダ。1人のユーザが複数のPCで同期して利用できるファイルを入れる
   282:   public static String sgsAppDataLocalFolder;  //Windowsのみ。AppData/Localフォルダ。1人のユーザがこのPCだけで利用できるファイルを入れる
   283:   public static String sgsHomeDirectory;  //ホームディレクトリ
   284:   public static String sgsCurrentDirectory;  //カレントディレクトリ
   285:   public static File sgsLocalIniFile;  //ローカルのみ。設定ファイル
   286:   public static String sgsLocalIniPath;  //ローカルのみ。設定ファイル名
   287:   public static boolean sgsSaveOnExit;  //true=終了時に設定を保存
   288:   public static JCheckBoxMenuItem sgsSaveOnExitCheckBox;
   289:   public static boolean sgsOpmtestOn;  //true=OPMテスト実行
   290:   public static String sgsSaveiconValue;
   291:   public static String sgsIrbbenchValue;
   292: 
   293:   public static HashMap<String,String> sgsDefaultMap;  //デフォルトの設定。SGS_DEFAULT_PARAMETERSを変換したもの
   294:   public static HashMap<String,String> sgsStartMap;  //開始時の設定。デフォルトの設定に言語などを加えたもの。これと異なる値を持つキーだけ保存する
   295:   public static HashMap<String,String> sgsCurrentMap;  //現在の設定
   296:   public static HashMap<String,HashMap<String,String>> sgsRootMap;  //保存されているすべての設定。設定名→設定。設定名""は現在の設定。設定のキー"_"は設定名
   297:   public static SGSInterface sgsInterface;  //設定インタフェイス
   298: 
   299:   public static JMenu sgsMenu;  //設定メニュー
   300: 
   301:   public static String[] sgsNameArray;  //設定名の配列
   302: 
   303:   //「設定に名前を付けて保存する」ウインドウ
   304:   public static JFrame sgsSaveSettingsAsFrame;
   305:   public static ScrollList sgsSaveSettingsAsScrollList;
   306:   public static JTextField sgsSaveSettingsAsTextField;
   307: 
   308:   //「名前を付けた設定を削除する」ウインドウ
   309:   public static JFrame sgsRemoveNamedSettingsFrame;
   310:   public static ScrollList sgsRemoveNamedSettingsScrollList;
   311:   public static JButton sgsRemoveNamedSettingsRemoveButton;
   312: 
   313:   //DictionaryComparator
   314:   //  辞書順コンパレータ
   315:   //  大文字と小文字を区別しない
   316:   //  数字の並びを数の大小で比較する
   317:   //  一致したときは改めて大文字と小文字を区別して数字を特別扱いしないで比較し直す
   318:   public static final Comparator<String> DictionaryComparator = new Comparator<String> () {
   319:     @Override public int compare (String s1, String s2) {
   320:       int l1 = s1.length ();
   321:       int l2 = s2.length ();
   322:       int b1, b2;  //部分文字列の開始位置(このインデックスを含む)
   323:       int e1, e2;  //部分文字列の終了位置(このインデックスを含まない)
   324:       int f = 0;  //比較結果
   325:     compare:
   326:       {
   327:         for (b1 = 0, b2 = 0; b1 < l1 && b2 < l2; b1 = e1, b2 = e2) {
   328:           int c1, c2;
   329:           //数字と数字以外の境目を探して部分文字列の終了位置にする
   330:           e1 = b1;
   331:           c1 = s1.charAt (e1);
   332:           c1 = ('0' - 1) - c1 & c1 - ('9' + 1);  //(c1<0)==isdigit(c1)
   333:           for (e1++; e1 < l1; e1++) {
   334:             c2 = s1.charAt (e1);
   335:             c2 = ('0' - 1) - c2 & c2 - ('9' + 1);  //(c2<0)==isdigit(c2)
   336:             if ((c1 ^ c2) < 0) {  //数字と数字以外の境目
   337:               break;
   338:             }
   339:             c1 = c2;
   340:           }
   341:           e2 = b2;
   342:           c1 = s2.charAt (e2);
   343:           c1 = ('0' - 1) - c1 & c1 - ('9' + 1);  //(c1<0)==isdigit(c1)
   344:           for (e2++; e2 < l2; e2++) {
   345:             c2 = s2.charAt (e2);
   346:             c2 = ('0' - 1) - c2 & c2 - ('9' + 1);  //(c2<0)==isdigit(c2)
   347:             if ((c1 ^ c2) < 0) {  //数字と数字以外の境目
   348:               break;
   349:             }
   350:             c1 = c2;
   351:           }
   352:           c1 = s1.charAt (b1);
   353:           c2 = s2.charAt (b2);
   354:           if ((('0' - 1) - c1 & c1 - ('9' + 1) & ('0' - 1) - c2 & c2 - ('9' + 1)) < 0) {  //両方数字のとき
   355:             //ゼロサプレスする
   356:             for (; b1 < e1 && s1.charAt (b1) == '0'; b1++) {
   357:             }
   358:             for (; b2 < e2 && s2.charAt (b2) == '0'; b2++) {
   359:             }
   360:             //桁数を比較する
   361:             f = (e1 - b1) - (e2 - b2);
   362:             if (f != 0) {
   363:               break compare;
   364:             }
   365:             //数字を比較する
   366:             for (; b1 < e1 && b2 < e2; b1++, b2++) {
   367:               f = s1.charAt (b1) - s2.charAt (b2);
   368:               if (f != 0) {
   369:                 break compare;
   370:               }
   371:             }
   372:           } else {  //どちらかが数字ではないとき
   373:             //大文字と小文字を区別しないで比較する
   374:             //  小文字化してから比較する
   375:             for (; b1 < e1 && b2 < e2; b1++, b2++) {
   376:               c1 = s1.charAt (b1);
   377:               c2 = s2.charAt (b2);
   378:               f = ((c1 + ((('A' - 1) - c1 & c1 - ('Z' + 1)) >> 31 & 'a' - 'A')) -
   379:                    (c2 + ((('A' - 1) - c2 & c2 - ('Z' + 1)) >> 31 & 'a' - 'A')));
   380:               if (f != 0) {
   381:                 break compare;
   382:               }
   383:             }
   384:             if (b1 < e1 || b2 < e2) {  //部分文字列が片方だけ残っているとき
   385:               //  一致したまま片方だけ残るのは両方数字以外のときだけ
   386:               //  部分文字列が先に終わった方は文字列が終わっているか数字が続いている
   387:               //  部分文字列が残っている方は数字ではないので1文字比較するだけで大小関係がはっきりする
   388:               //f = (b1 < l1 ? s1.charAt (b1) : -1) - (b2 < l2 ? s2.charAt (b2) : -1);
   389:               f = (e1 - b1) - (e2 - b2);  //部分文字列が片方だけ残っているときは残っている方が大きい
   390:               break compare;
   391:             }
   392:           }  //if 両方数字のとき/どちらかが数字ではないとき
   393:         }  //for b1,b2
   394:         f = (l1 - b1) - (l2 - b2);  //文字列が片方だけ残っているときは残っている方が大きい
   395:         //一致したときは改めて大文字と小文字を区別して数字を特別扱いしないで比較し直す
   396:         if (f == 0) {
   397:           for (b1 = 0, b2 = 0; b1 < l1 && b2 < l2; b1++, b2++) {
   398:             f = s1.charAt (b1) - s2.charAt (b2);
   399:             if (f != 0) {
   400:               break compare;
   401:             }
   402:           }
   403:         }
   404:       }  //compare
   405:       return (f >> 31) - (-f >> 31);
   406:     }  //compare(String,String)
   407:   };  //DictionaryComparator
   408: 
   409:   //sgsInit ()
   410:   //  設定の初期化
   411:   public static void sgsInit () {
   412: 
   413:     sgsAppDataRoamingFolder = null;
   414:     sgsAppDataLocalFolder = null;
   415:     sgsHomeDirectory = null;
   416:     sgsCurrentDirectory = null;
   417:     sgsLocalIniFile = null;
   418:     sgsLocalIniPath = null;
   419:     sgsSaveOnExit = true;
   420:     sgsSaveOnExitCheckBox = null;
   421: 
   422:     sgsOpmtestOn = false;
   423:     sgsSaveiconValue = null;
   424:     sgsIrbbenchValue = null;
   425: 
   426:     //デフォルトの設定
   427:     //  SGS_DEFAULT_PARAMETERSを分解してデフォルトの設定sgsDefaultMapを作る
   428:     //  デフォルトの設定sgsDefaultMapには設定名を表すキー"_"が存在しない
   429:     sgsDefaultMap = new HashMap<String,String> ();
   430:     String[] a = SGS_DEFAULT_PARAMETERS.split (";");
   431:     for (int i = 0, l = a.length; i < l; i += 2) {
   432:       String key = a[i];
   433:       String value = i + 1 < l ? a[i + 1] : "";  //splitで末尾の空要素が削除されるのでa[i+1]が存在しないとき""とみなす
   434:       sgsDefaultMap.put (key, value);
   435:     }
   436:     //  ウインドウの位置とサイズと状態
   437:     for (String key : SGS_FRAME_KEYS) {
   438:       sgsDefaultMap.put (key + "rect", "0,0,0,0");  //ウインドウの位置とサイズ(x,y,width,height)
   439:       sgsDefaultMap.put (key + "stat", "normal");  //ウインドウの状態(iconified/maximized/h-maximized/v-maximized/normal)
   440:       sgsDefaultMap.put (key + "open", "off");  //ウインドウが開いているかどうか。メインのフレームも終了時にはoffになっている
   441:     }
   442: 
   443:     //開始時の設定
   444:     //  デフォルトの設定sgsDefaultMapのコピーに言語やホームディレクトリを追加して開始時の設定sgsStartMapを作る
   445:     //  開始時の設定sgsStartMapには設定名を表すキー"_"が存在しない
   446:     sgsStartMap = new HashMap<String,String> (sgsDefaultMap);
   447:     //  言語
   448:     switch (Locale.getDefault ().getLanguage ()) {  //動作環境の言語
   449:     case "ja":
   450:       sgsStartMap.put ("lang", "ja");
   451:       break;
   452:     }
   453:     if (XEiJ.prgIsLocal) {  //ローカルのとき
   454:       if (false) {
   455:         //すべての環境変数を表示する
   456:         //  System.getenv()はコマンドラインのみ。アプレットとJNLPではブロックされる
   457:         System.out.println ("\n[System.getenv()]");
   458:         new TreeMap<String,String> (System.getenv ()).forEach ((k, v) -> System.out.println (k + " = " + v));  //System.getenv()はMap<String,String>
   459:       }
   460:       if (false) {
   461:         //すべてのプロパティを表示する
   462:         //  System.getProperties()はコマンドラインのみ。アプレットとJNLPではブロックされる
   463:         System.out.println ("\n[System.getProperties()]");
   464:         TreeMap<String,String> m = new TreeMap<String,String> ();
   465:         System.getProperties ().forEach ((k, v) -> m.put (k.toString (), v.toString ()));  //System.getProperties()はHashtable<Object,Object>
   466:         m.forEach ((k, v) -> System.out.println (k + " = " + v));
   467:       }
   468:       //  AppDataフォルダ
   469:       boolean isWindows = System.getProperty ("os.name").indexOf ("Windows") >= 0;  //true=Windows
   470:       sgsAppDataRoamingFolder = isWindows ? System.getenv ("APPDATA") : null;
   471:       sgsAppDataLocalFolder = isWindows ? System.getenv ("LOCALAPPDATA") : null;
   472:       //  ホームディレクトリ
   473:       //    new File("")
   474:       sgsHomeDirectory = System.getProperty ("user.home");
   475:       //  カレントディレクトリ
   476:       //    new File(".")
   477:       sgsCurrentDirectory = System.getProperty ("user.dir");
   478:       //  設定ファイル名
   479:       sgsLocalIniFile = new File ((sgsAppDataRoamingFolder != null ? sgsAppDataRoamingFolder + File.separator + SGS_APPDATA_FOLDER :
   480:                                    sgsHomeDirectory != null ? sgsHomeDirectory :
   481:                                    sgsCurrentDirectory != null ? sgsCurrentDirectory :
   482:                                    ".") + File.separator + SGS_INI).getAbsoluteFile ();
   483:       sgsLocalIniPath = sgsLocalIniFile.getPath ();
   484:       //  その他
   485:       sgsStartMap.put ("hf0", sgsHomeDirectory != null ? sgsHomeDirectory : HFS.HFS_DUMMY_UNIT_NAME);
   486:     } else {  //ローカルでないとき
   487:       sgsStartMap.put ("hf0", HFS.HFS_DUMMY_UNIT_NAME);
   488:     }
   489:     //  ウインドウに合わせる
   490:     //    アプレットのときは固定サイズ、JNLPまたはローカルのときはウインドウに合わせる
   491:     sgsStartMap.put ("fitinwindow", XEiJ.prgIsApplet ? "off" : "on");
   492: 
   493:     //現在の設定
   494:     //  開始時の設定sgsStartMapをコピーして現在の設定sgsCurrentMapを作る
   495:     //  ここで初めて設定名を表すキー"_"を追加する
   496:     sgsCurrentMap = new HashMap<String,String> (sgsStartMap);
   497:     sgsCurrentMap.put ("_", "");
   498: 
   499:     //保存されているすべての設定のマップ
   500:     sgsRootMap = new HashMap<String,HashMap<String,String>> ();
   501:     sgsRootMap.put ("", sgsCurrentMap);
   502: 
   503:     //設定インタフェイス
   504:     sgsInterface = (XEiJ.prgIsApplet ? new SGSApplet () :
   505:                     XEiJ.prgIsJnlp ? new SGSJnlp () :
   506:                     new SGSLocal ());
   507: 
   508:     //設定ファイルを読み込む
   509:     sgsLoadSettings ();
   510: 
   511:     if (XEiJ.prgIsLocal) {  //ローカルのとき
   512:       if (sgsIrbbenchValue != null) {
   513:         InstructionBenchmark.irbBench (sgsIrbbenchValue);
   514:         System.exit (0);
   515:       }
   516:     }
   517: 
   518:   }  //sgsInit()
   519: 
   520:   //sgsTini ()
   521:   //  後始末
   522:   public static void sgsTini () {
   523:     if (sgsSaveOnExit) {  //終了時に設定を保存
   524:       sgsSaveAllSettings ();
   525:     }
   526:   }  //sgsTini()
   527: 
   528:   //sgsMakeMenu ()
   529:   //  「設定」メニューを作る
   530:   public static void sgsMakeMenu () {
   531:     //アクションリスナー
   532:     ActionListener listener = new ActionListener () {
   533:       @Override public void actionPerformed (ActionEvent ae) {
   534:         Object source = ae.getSource ();
   535:         String command = ae.getActionCommand ();
   536:         switch (command) {
   537:         case "Save Settings on Exit":  //終了時に設定を保存
   538:           sgsSaveOnExit = ((JCheckBoxMenuItem) ae.getSource ()).isSelected ();
   539:           break;
   540:         case "Save Settings Now":  //今すぐ設定を保存
   541:           sgsSaveAllSettings ();
   542:           break;
   543:         case "Save Settings As":  //設定に名前を付けて保存
   544:           if (SGS_NAMED_SETTINGS && XEiJ.prgIsLocal) {
   545:             sgsSaveSettingsAs ();
   546:           }
   547:           break;
   548:         case "Remove Named Settings":  //名前を付けた設定を削除
   549:           if (SGS_NAMED_SETTINGS && XEiJ.prgIsLocal) {
   550:             sgsRemoveNamedSettings ();
   551:           }
   552:           break;
   553:         case "Remove All Settings":  //すべての設定を削除
   554:           sgsRemoveAllSettings ();
   555:           break;
   556:         }
   557:       }
   558:     };
   559:     //メニュー
   560:     sgsMenu = Multilingual.mlnText (
   561:       ComponentFactory.createMenu (
   562:         "Configuration File",
   563:         sgsSaveOnExitCheckBox = Multilingual.mlnText (ComponentFactory.createCheckBoxMenuItem (sgsSaveOnExit, "Save Settings on Exit", listener), "ja", "終了時に設定を保存"),
   564:         Multilingual.mlnText (ComponentFactory.createMenuItem ("Save Settings Now", listener), "ja", "今すぐ設定を保存"),
   565:         SGS_NAMED_SETTINGS ? ComponentFactory.setEnabled (Multilingual.mlnText (ComponentFactory.createMenuItem ("Save Settings As", listener), "ja", "設定に名前を付けて保存"), XEiJ.prgIsLocal) : null,
   566:         SGS_NAMED_SETTINGS ? ComponentFactory.setEnabled (Multilingual.mlnText (ComponentFactory.createMenuItem ("Remove Named Settings", listener), "ja", "名前を付けた設定を削除"), XEiJ.prgIsLocal) : null,
   567:         ComponentFactory.createHorizontalSeparator (),
   568:         Multilingual.mlnText (ComponentFactory.createMenuItem ("Remove All Settings", listener), "ja", "すべての設定を削除")),
   569:       "ja", "設定ファイル");
   570:   }  //sgsMakeMenu()
   571: 
   572:   //sgsLoadSettings ()
   573:   //  設定ファイルを読み込む
   574:   public static void sgsLoadSettings () {
   575: 
   576:     //コマンドラインなどのパラメータを読み取る
   577:     //  ローカルのときはここで設定ファイル名が変更される場合がある
   578:     HashMap<String,String> map = sgsInterface.sgiGetParameters ();
   579: 
   580:     //設定ファイルを読み込んですべての設定sgsRootMapに格納する
   581:     sgsDecodeRootMap (sgsInterface.sgiLoad ());
   582: 
   583:     //コマンドラインなどのパラメータで使用する設定を選択する
   584:     if (map.containsKey ("config")) {  //キー"config"が指定されているとき
   585:       String name = map.get ("config");  //使用する設定名
   586:       if (name.equals ("default")) {  //デフォルトの設定
   587:         sgsCurrentMap.clear ();  //古いマップを消しておく
   588:         sgsCurrentMap = new HashMap<String,String> (sgsStartMap);  //開始時の設定を現在の設定にコピーする
   589:         sgsCurrentMap.put ("_", "");  //設定名を加える
   590:         sgsRootMap.put ("", sgsCurrentMap);  //新しいマップを繋ぎ直す
   591:       } else if (name.length () != 0 &&  //使用する設定名が""以外で
   592:                  sgsRootMap.containsKey (name)) {  //存在するとき
   593:         sgsCurrentMap.clear ();  //古いマップを消しておく
   594:         sgsCurrentMap = new HashMap<String,String> (sgsRootMap.get (name));  //指定された設定を現在の設定にコピーする
   595:         sgsCurrentMap.put ("_", "");  //設定名を元に戻す
   596:         sgsRootMap.put ("", sgsCurrentMap);  //新しいマップを繋ぎ直す
   597:       }
   598:       map.remove ("config");  //キー"config"は指定されなかったことにする
   599:     }
   600: 
   601:     //コマンドラインなどのパラメータを現在の設定に上書きする
   602:     //map.forEach ((k, v) -> sgsCurrentMap.put (k, v));
   603:     for (String key : map.keySet ()) {
   604:       sgsCurrentMap.put (key, map.get (key));
   605:     }
   606: 
   607:     String s;
   608:     String[] a;
   609: 
   610:     //PRG
   611:     XEiJ.prgLang = sgsCurrentMap.get ("lang").toLowerCase ().equals ("ja") ? "ja" : "en";  //言語
   612:     XEiJ.prgVerbose = sgsCurrentMap.get ("verbose").equals ("on");  //冗長表示
   613:     //SGS
   614:     sgsSaveOnExit = sgsCurrentMap.get ("saveonexit").equals ("on");  //終了時に設定を保存
   615:     //LNF
   616:     //  色
   617:     a = sgsCurrentMap.get ("hhssbb").split (",");
   618:     if (a.length == 6) {
   619:       LnF.lnfH0 = XEiJ.fmtParseInt (a[0], 0, 0, 2000, LnF.LNF_H0);
   620:       LnF.lnfH1 = XEiJ.fmtParseInt (a[1], 0, 0, 2000, LnF.LNF_H1);
   621:       LnF.lnfS0 = XEiJ.fmtParseInt (a[2], 0, 0, 1000, LnF.LNF_S0);
   622:       LnF.lnfS1 = XEiJ.fmtParseInt (a[3], 0, 0, 1000, LnF.LNF_S1);
   623:       LnF.lnfB0 = XEiJ.fmtParseInt (a[4], 0, 0, 1000, LnF.LNF_B0);
   624:       LnF.lnfB1 = XEiJ.fmtParseInt (a[5], 0, 0, 1000, LnF.LNF_B1);
   625:     } else {
   626:       LnF.lnfH0 = LnF.LNF_H0;
   627:       LnF.lnfH1 = LnF.LNF_H1;
   628:       LnF.lnfS0 = LnF.LNF_S0;
   629:       LnF.lnfS1 = LnF.LNF_S1;
   630:       LnF.lnfB0 = LnF.LNF_B0;
   631:       LnF.lnfB1 = LnF.LNF_B1;
   632:     }
   633:     //KBD
   634:     //  キーボードの種類
   635:     s = sgsCurrentMap.get ("keyboard").toLowerCase ();
   636:     Keyboard.kbdOn = !s.equals ("none");
   637:     Keyboard.kbdType = s.equals ("compact") ? Keyboard.KBD_COMPACT_TYPE : Keyboard.KBD_STANDARD_TYPE;
   638:     //PNL
   639:     XEiJ.pnlFullscreenOn = false;  //sgsCurrentMap.get ("fullscreen").equals ("on");  //全画面表示
   640:     XEiJ.pnlPrevFitInWindowOn = XEiJ.pnlFitInWindowOn = !XEiJ.prgIsApplet && sgsCurrentMap.get ("fitinwindow").equals ("on");  //ウインドウに合わせる
   641:     XEiJ.pnlFixedScale = XEiJ.fmtParseInt (sgsCurrentMap.get ("fixedscale"), 0, 10, 1000, 100);  //固定サイズの倍率
   642:     //  補間アルゴリズム
   643:     s = sgsCurrentMap.get ("interpolation").toLowerCase ();
   644:     XEiJ.pnlInterpolation = (s.equals ("bicubic") ? RenderingHints.VALUE_INTERPOLATION_BICUBIC :  //三次補間
   645:                              s.equals ("bilinear") ? RenderingHints.VALUE_INTERPOLATION_BILINEAR :  //線形補間
   646:                              RenderingHints.VALUE_INTERPOLATION_NEAREST_NEIGHBOR);  //最近傍補間
   647:     //MUS
   648:     XEiJ.musSeamlessOn = sgsCurrentMap.get ("seamless").equals ("on");  //シームレス/エクスクルーシブ
   649:     XEiJ.musCtrlRightOn = sgsCurrentMap.get ("ctrlright").equals ("on");  //Ctrlキー+左ボタンを右ボタンとみなす
   650:     XEiJ.musEdgeAccelerationOn = sgsCurrentMap.get ("edgeaccel").equals ("on");  //縁部加速
   651:     Z8530.scc0ScaleIndex = XEiJ.fmtParseInt (sgsCurrentMap.get ("mousespeed"), 0, 0, 40, 20);  //マウスカーソルの速度
   652:     XEiJ.musHostsPixelUnitsOn = sgsCurrentMap.get ("hostspixelunits").equals ("on");  //ホストの画素単位で動く
   653:     //MPU
   654:     //  機種
   655:     s = sgsCurrentMap.get ("model").toLowerCase ();
   656:     XEiJ.mdlModel = (s.equals ("expert") ? XEiJ.MDL_EXPERT :
   657:                      s.equals ("super") ? XEiJ.MDL_SUPER :
   658:                      s.equals ("xvi") ? XEiJ.MDL_XVI :
   659:                      s.equals ("compact") ? XEiJ.MDL_COMPACT :
   660:                      s.equals ("hybrid") ? XEiJ.MDL_HYBRID :
   661:                      s.equals ("x68030") ? XEiJ.MDL_X68030 :
   662:                      s.equals ("060turbo") ? XEiJ.MDL_060TURBO :
   663:                      XEiJ.MDL_HYBRID);
   664:     //  MPU
   665:     s = sgsCurrentMap.get ("mpu");
   666:     XEiJ.mdlCoreRequest = (s.equals ("0") ? 0 :
   667:                            s.equals ("3") ? 3 :
   668:                            s.equals ("6") ? 6 :
   669:                            XEiJ.mdlModel == XEiJ.MDL_EXPERT ||
   670:                            XEiJ.mdlModel == XEiJ.MDL_SUPER ||
   671:                            XEiJ.mdlModel == XEiJ.MDL_XVI ||
   672:                            XEiJ.mdlModel == XEiJ.MDL_COMPACT ||
   673:                            XEiJ.mdlModel == XEiJ.MDL_HYBRID ? 0 :
   674:                            XEiJ.mdlModel == XEiJ.MDL_X68030 ? 3 :
   675:                            XEiJ.mdlModel == XEiJ.MDL_060TURBO ? 6 :
   676:                            0);
   677:     //  クロック
   678:     s = sgsCurrentMap.get ("clock").toLowerCase ();
   679:     switch (s) {
   680:     case "expert":
   681:     case "super":
   682:       XEiJ.mdlClockRequest = 10.0;
   683:       XEiJ.mpuUtilOn = false;
   684:       break;
   685:     case "xvi":
   686:       XEiJ.mdlClockRequest = 50.0 / 3.0;  //16.7MHz
   687:       XEiJ.mpuUtilOn = false;
   688:       break;
   689:     case "compact":
   690:     case "x68030":
   691:       XEiJ.mdlClockRequest = 25.0;
   692:       XEiJ.mpuUtilOn = false;
   693:       break;
   694:     case "hybrid":
   695:       XEiJ.mdlClockRequest = 100.0 / 3.0;  //33.3MHz
   696:       XEiJ.mpuUtilOn = false;
   697:       break;
   698:     default:
   699:       if (s.matches ("^(?:" +
   700:                      "[-+]?" +  //符号
   701:                      "(?:[0-9]+(?:\\.[0-9]*)?|\\.[0-9]+)" +  //仮数部
   702:                      "(?:[Ee][-+]?[0-9]+)?" +  //指数部
   703:                      ")$")) {
   704:         double d = Double.parseDouble (s);
   705:         if (1.0 <= d && d <= 1000.0) {
   706:           XEiJ.mdlClockRequest = d;
   707:           XEiJ.mpuUtilOn = false;
   708:         }
   709:       } else {
   710:         XEiJ.mdlClockRequest = (XEiJ.mdlModel == XEiJ.MDL_EXPERT ||
   711:                                 XEiJ.mdlModel == XEiJ.MDL_SUPER ? 10.0 :
   712:                                 XEiJ.mdlModel == XEiJ.MDL_XVI ? 50.0 / 3.0 :  //16.7MHz
   713:                                 XEiJ.mdlModel == XEiJ.MDL_COMPACT ||
   714:                                 XEiJ.mdlModel == XEiJ.MDL_HYBRID ? 100.0 / 3.0 :  //33.3MHz
   715:                                 XEiJ.mdlModel == XEiJ.MDL_X68030 ? 25.0 :
   716:                                 XEiJ.mdlModel == XEiJ.MDL_060TURBO ? 50.0 :
   717:                                 100.0 / 3.0);  //33.3MHz
   718:       }
   719:     }
   720:     XEiJ.mdlIPLROMRequest = (XEiJ.mdlModel == XEiJ.MDL_EXPERT ||
   721:                              XEiJ.mdlModel == XEiJ.MDL_SUPER ? 0 :
   722:                              XEiJ.mdlModel == XEiJ.MDL_XVI ? 1 :
   723:                              XEiJ.mdlModel == XEiJ.MDL_COMPACT ? 2:
   724:                              XEiJ.mdlModel == XEiJ.MDL_HYBRID ||
   725:                              XEiJ.mdlModel == XEiJ.MDL_X68030 ||
   726:                              XEiJ.mdlModel == XEiJ.MDL_060TURBO ? 3 :  //5は不可
   727:                              3);
   728:     XEiJ.mdlSCSIINRequest = (XEiJ.mdlModel == XEiJ.MDL_EXPERT ? true :
   729:                              XEiJ.mdlModel == XEiJ.MDL_SUPER ||
   730:                              XEiJ.mdlModel == XEiJ.MDL_XVI ||
   731:                              XEiJ.mdlModel == XEiJ.MDL_COMPACT ||
   732:                              XEiJ.mdlModel == XEiJ.MDL_HYBRID ||
   733:                              XEiJ.mdlModel == XEiJ.MDL_X68030 ||
   734:                              XEiJ.mdlModel == XEiJ.MDL_060TURBO ? false :
   735:                              false);
   736:     XEiJ.mpuUtilOn = sgsCurrentMap.get ("util").equals ("on");  //任意の負荷率
   737:     XEiJ.mpuUtilRatio = XEiJ.fmtParseInt (sgsCurrentMap.get ("ratio"), 0, 1, 100, 90);  //任意の負荷率
   738:     XEiJ.mpuArbFreqMHz = XEiJ.fmtParseInt (sgsCurrentMap.get ("mhz"), 0, 1, 1000, 100);  //任意の周波数
   739:     if (XEiJ.mpuUtilOn) {
   740:       XEiJ.mpuArbFreqOn = false;
   741:     } else {
   742:       XEiJ.mpuArbFreqOn = !(XEiJ.mdlClockRequest == 10.0 ||
   743:                             XEiJ.mdlClockRequest == 50.0 / 3.0 ||  //16.7MHz
   744:                             XEiJ.mdlClockRequest == 25.0 ||
   745:                             XEiJ.mdlClockRequest == 100.0 / 3.0 ||  //33.3MHz
   746:                             XEiJ.mdlClockRequest == 50.0);
   747:       if (XEiJ.mpuArbFreqOn) {
   748:         XEiJ.mpuArbFreqMHz = (int) XEiJ.mdlClockRequest;
   749:       }
   750:     }
   751:     //FPU
   752:     XEiJ.fpuMode = XEiJ.fmtParseInt (sgsCurrentMap.get ("fpumode"), 0, 0, 2, 1);  //FPUモード
   753:     XEiJ.fpuOn = XEiJ.mdlCoreRequest >= 2 && XEiJ.fpuMode != 0;
   754:     XEiJ.fpuFullSpec = sgsCurrentMap.get ("fullspecfpu").equals ("on");  //フルスペックFPU
   755:     //FPK
   756:     FEFunction.fpkOn = sgsCurrentMap.get ("fefunc").equals ("on");  //FEファンクション命令
   757:     FEFunction.fpkRejectFloatOn = sgsCurrentMap.get ("rejectfloat").equals ("on");  //FLOATn.Xを組み込まない
   758:     //BUS
   759:     XEiJ.busHighMemorySize = XEiJ.fmtParseInt (sgsCurrentMap.get ("highmemory"), 0, 0, 16, 16) << 20;  //X68030のハイメモリのサイズ
   760:     if (!(XEiJ.busHighMemorySize == 0 << 20 ||
   761:           XEiJ.busHighMemorySize == 16 << 20)) {
   762:       XEiJ.busHighMemorySize = 16 << 20;
   763:     }
   764:     XEiJ.busHighMemorySaveOn = XEiJ.prgIsLocal && sgsCurrentMap.get ("highmemorysave").equals ("on");  //X68030のハイメモリの内容を保存する
   765:     XEiJ.busHighMemoryData = XEiJ.prgIsLocal && XEiJ.busHighMemorySaveOn ? sgsCurrentMap.get ("highmemorydata") : "";  //X68030のハイメモリの内容(gzip+base64)
   766:     XEiJ.busLocalMemorySize = XEiJ.fmtParseInt (sgsCurrentMap.get ("localmemory"), 0, 0, 256, 128) << 20;  //060turboのローカルメモリのサイズ(MB)
   767:     if (!(XEiJ.busLocalMemorySize == 0 << 20 ||
   768:           XEiJ.busLocalMemorySize == 16 << 20 ||
   769:           XEiJ.busLocalMemorySize == 32 << 20 ||
   770:           XEiJ.busLocalMemorySize == 64 << 20 ||
   771:           XEiJ.busLocalMemorySize == 128 << 20 ||
   772:           XEiJ.busLocalMemorySize == 256 << 20)) {
   773:       XEiJ.busLocalMemorySize = 128 << 20;
   774:     }
   775:     XEiJ.busLocalMemorySaveOn = XEiJ.prgIsLocal && sgsCurrentMap.get ("localmemorysave").equals ("on");  //060turboのローカルメモリの内容を保存する
   776:     XEiJ.busLocalMemoryData = XEiJ.prgIsLocal && XEiJ.busLocalMemorySaveOn ? sgsCurrentMap.get ("localmemorydata") : "";  //060turboのローカルメモリの内容(gzip+base64)
   777:     XEiJ.busRequestCutFC2Pin = sgsCurrentMap.get ("cutfc2pin").equals ("on");  //FC2ピンをカットする(on/off)
   778:     //MMR
   779:     MainMemory.mmrMemorySizeRequest = XEiJ.fmtParseInt (sgsCurrentMap.get ("memory"), 0, 1, 12, 12) << 20;  //メインメモリのサイズ
   780:     if (MainMemory.mmrMemorySizeRequest > 1 << 20 && (MainMemory.mmrMemorySizeRequest & 1 << 20) != 0) {  //3,5,7,9,11は不可
   781:       MainMemory.mmrMemorySizeRequest = 12 << 20;
   782:     }
   783:     if (MainMemory.MMR_SAVE) {
   784:       MainMemory.mmrMemorySaveOn = XEiJ.prgIsLocal && sgsCurrentMap.get ("memorysave").equals ("on");  //メインメモリの内容を保存する
   785:       MainMemory.mmrMemoryData = XEiJ.prgIsLocal && MainMemory.mmrMemorySaveOn ? sgsCurrentMap.get ("memorydata") : "";  //メインメモリの内容
   786:     }
   787:     //CRT
   788:     if (CRTC.CRT_ENABLE_INTERMITTENT) {
   789:       CRTC.crtIntermittentInterval = XEiJ.fmtParseInt (sgsCurrentMap.get ("intermittent"), 0, 0, 4, 0);  //間欠描画
   790:     }
   791:     if (CRTC.CRT_EXTENDED_GRAPHICS) {
   792:       CRTC.crtExtendedGraphicsRequest = sgsCurrentMap.get ("extendedgraphics").equals ("on");  //拡張グラフィックス画面
   793:     }
   794:     //SND
   795:     SoundSource.sndPlayOn = sgsCurrentMap.get ("sound").equals ("on");  //音声出力
   796:     SoundSource.sndVolume = XEiJ.fmtParseInt (sgsCurrentMap.get ("volume"), 0, 0, SoundSource.SND_VOLUME_MAX, SoundSource.SND_VOLUME_DEFAULT);  //ボリューム
   797:     s = sgsCurrentMap.get ("soundinterpolation").toLowerCase ();
   798:     SoundSource.sndRateConverter = (s.equals ("thinning") ? SoundSource.SND_CHANNELS == 1 ? SoundSource.SNDRateConverter.THINNING_MONO : SoundSource.SNDRateConverter.THINNING_STEREO :  //間引き
   799:                              s.equals ("linear") ? SoundSource.SND_CHANNELS == 1 ? SoundSource.SNDRateConverter.LINEAR_MONO : SoundSource.SNDRateConverter.LINEAR_STEREO :  //線形補間
   800:                              s.equals ("constant-area") ? SoundSource.SNDRateConverter.CONSTANT_AREA_STEREO_48000 :  //区分定数面積補間
   801:                         s.equals ("linear-area") ? SoundSource.SNDRateConverter.LINEAR_AREA_STEREO_48000 :  //線形面積補間
   802:                              SoundSource.SND_CHANNELS == 1 ? SoundSource.SNDRateConverter.LINEAR_MONO : SoundSource.SNDRateConverter.LINEAR_STEREO);  //線形補間
   803:     //OPM
   804:     YM2151.opmOutputMask = sgsCurrentMap.get ("opmoutput").equals ("on") ? -1 : 0;  //OPM出力
   805:     //PCM
   806:     ADPCM.pcmOutputOn = sgsCurrentMap.get ("pcmoutput").equals ("on");  //PCM出力
   807:     s = sgsCurrentMap.get ("pcminterpolation").toLowerCase ();
   808:     ADPCM.pcmInterpolationAlgorithm = (s.equals ("constant") ? ADPCM.PCM_INTERPOLATION_CONSTANT :  //区分定数補間
   809:                                       s.equals ("linear") ? ADPCM.PCM_INTERPOLATION_LINEAR :  //線形補間
   810:                                       s.equals ("hermite") ? ADPCM.PCM_INTERPOLATION_HERMITE :  //エルミート補間
   811:                                       ADPCM.PCM_INTERPOLATION_LINEAR);  //線形補間
   812:     ADPCM.pcmOSCFreqRequest = XEiJ.fmtParseInt (sgsCurrentMap.get ("pcmoscfreq"), 0, 0, 1, 0);  //原発振周波数
   813:     //FDC
   814:     //!!!
   815:     //HDC
   816:     //!!!
   817:     //SPC
   818:     //!!!
   819:     //PPI
   820:     //  ジョイスティック
   821:     XEiJ.ppiJoyKey = sgsCurrentMap.get ("joykey").equals ("on");
   822:     XEiJ.ppiJoyAuto = sgsCurrentMap.get ("joyauto").equals ("on");
   823:     XEiJ.ppiJoyBlock = sgsCurrentMap.get ("joyblock").equals ("on");
   824:     XEiJ.ppiParseParam (sgsCurrentMap.get ("joymap"));
   825:     //HFS
   826:     //!!!
   827:     //EXS
   828:     SPC.spcSCSIEXROM = sgsCurrentMap.get ("scsiexrom");  //拡張SCSI ROMイメージファイル名
   829:     SPC.spcSCSIEXRequest = sgsCurrentMap.get ("scsiex").equals ("on");  //拡張SCSIポートの有無
   830:     //SMR
   831:     XEiJ.smrSramName = sgsCurrentMap.get ("sram");  //SRAMイメージファイル名
   832:     XEiJ.smrSramData = sgsCurrentMap.get ("sramdata");  //SRAMの内容
   833:     {
   834:       int sramsize = XEiJ.fmtParseInt (sgsCurrentMap.get ("sramsize"), 0, 16, 64, 0);  //SRAMの容量
   835:       if (sramsize == 16 || sramsize == 32 || sramsize == 64) {
   836:         XEiJ.smrSramSizeRequest = sramsize << 10;
   837:       }
   838:     }
   839:     XEiJ.smrRepeatDelay = XEiJ.fmtParseInt (sgsCurrentMap.get ("keydly"), 0, -1, 15, -1);  //リピートディレイ
   840:     XEiJ.smrRepeatInterval = XEiJ.fmtParseInt (sgsCurrentMap.get ("keyrep"), 0, -1, 15, -1);  //リピートインターバル
   841:     //  起動デバイス
   842:     //XEiJ.smrBootDevice = -1;  //起動デバイス
   843:     //XEiJ.smrBootROM = -1;  //ROM起動ハンドル
   844:     //XEiJ.smrBootRAM = -1;  //RAM起動アドレス
   845:     XEiJ.smrParseBootDevice (sgsCurrentMap.get ("boot"));
   846:     //ROM
   847:     XEiJ.romROMName = sgsCurrentMap.get ("rom");
   848:     XEiJ.romIPLROMName = sgsCurrentMap.get ("iplrom");
   849:     XEiJ.romROMDBOn = sgsCurrentMap.get ("romdb").equals ("on");
   850:     XEiJ.romSCSIINROMName = sgsCurrentMap.get ("scsiinrom");
   851:     XEiJ.romROM30Name = sgsCurrentMap.get ("rom30");
   852:     //FNT
   853:     FontEditor.fntCGROMName = sgsCurrentMap.get ("cgrom");
   854:     FontEditor.fntOmusubiOn = sgsCurrentMap.get ("omusubi").equals ("on");
   855:     //PRN
   856:     PrinterPort.prnAutosaveOn = sgsCurrentMap.get ("prnauto").equals ("on");
   857:     PrinterPort.prnSavePath = sgsCurrentMap.get ("prnpath");
   858: 
   859:     //ウインドウの位置とサイズと状態
   860:     for (String key : SGS_FRAME_KEYS) {
   861:       //ウインドウの位置とサイズ
   862:       a = sgsCurrentMap.get (key + "rect").split (",");
   863:       if (a.length == 4) {
   864:         RestorableFrame.rfmSetBounds (key,
   865:                                       new Rectangle (XEiJ.fmtParseInt (a[0], 0, -4096, 4096, 0),
   866:                                                      XEiJ.fmtParseInt (a[1], 0, -4096, 4096, 0),
   867:                                                      XEiJ.fmtParseInt (a[2], 0, 64, 4096, 0),
   868:                                                      XEiJ.fmtParseInt (a[3], 0, 64, 4096, 0)));
   869:       }
   870:       //ウインドウの状態
   871:       s = sgsCurrentMap.get (key + "stat").toLowerCase ();
   872:       RestorableFrame.rfmSetState (key,
   873:                                    s.equals ("iconified") ? Frame.ICONIFIED :  //アイコン化する
   874:                                    s.equals ("maximized") ? Frame.MAXIMIZED_BOTH :  //最大化する
   875:                                    s.equals ("h-maximized") ? Frame.MAXIMIZED_HORIZ :  //水平方向だけ最大化する
   876:                                    s.equals ("v-maximized") ? Frame.MAXIMIZED_VERT :  //垂直方向だけ最大化する
   877:                                    Frame.NORMAL);  //通常表示
   878:       //ウインドウが開いているかどうか
   879:       RestorableFrame.rfmSetOpened (key, sgsCurrentMap.get (key + "open").equals ("on"));
   880:     }
   881: 
   882:   }  //sgsLoadSettings()
   883: 
   884:   //sgsSaveAllSettings ()
   885:   //  設定ファイルを保存する
   886:   public static void sgsSaveAllSettings () {
   887:     //PRG
   888:     sgsCurrentMap.put ("lang", XEiJ.prgLang);  //言語
   889:     sgsCurrentMap.put ("verbose", XEiJ.prgVerbose ? "on" : "off");  //冗長表示
   890:     //SGS
   891:     sgsCurrentMap.put ("saveonexit", sgsSaveOnExit ? "on" : "off");  //終了時に設定を保存
   892:     //LNF
   893:     sgsCurrentMap.put ("hhssbb", LnF.lnfH0 + "," + LnF.lnfH1 + "," + LnF.lnfS0 + "," + LnF.lnfS1 + "," + LnF.lnfB0 + "," + LnF.lnfB1);  //色
   894:     //KBD
   895:     //  キーボードの種類
   896:     sgsCurrentMap.put ("keyboard",
   897:                        !Keyboard.kbdOn ? "none" :
   898:                        Keyboard.kbdType == Keyboard.KBD_COMPACT_TYPE ? "compact" :
   899:                        Keyboard.kbdType == Keyboard.KBD_STANDARD_TYPE ? "standard" :
   900:                        "standard");
   901:     //PNL
   902:     sgsCurrentMap.put ("fullscreen", XEiJ.pnlFullscreenOn ? "on" : "off");  //全画面表示
   903:     sgsCurrentMap.put ("fitinwindow", (XEiJ.pnlFullscreenOn ? XEiJ.pnlPrevFitInWindowOn : XEiJ.pnlFitInWindowOn) ? "on" : "off");  //ウインドウに合わせる
   904:     sgsCurrentMap.put ("fixedscale", String.valueOf (XEiJ.pnlFixedScale));  //固定サイズの倍率
   905:     //  補間アルゴリズム
   906:     sgsCurrentMap.put ("interpolation",
   907:                        XEiJ.pnlInterpolation == RenderingHints.VALUE_INTERPOLATION_NEAREST_NEIGHBOR ? "nearest" :
   908:                        XEiJ.pnlInterpolation == RenderingHints.VALUE_INTERPOLATION_BILINEAR ? "bilinear" :
   909:                        XEiJ.pnlInterpolation == RenderingHints.VALUE_INTERPOLATION_BICUBIC ? "bicubic" :
   910:                        "bilinear");
   911:     //MUS
   912:     sgsCurrentMap.put ("seamless", XEiJ.musSeamlessOn ? "on" : "off");  //シームレス/エクスクルーシブ
   913:     sgsCurrentMap.put ("ctrlright", XEiJ.musCtrlRightOn ? "on" : "off");  //Ctrlキー+左ボタンを右ボタンとみなす
   914:     sgsCurrentMap.put ("edgeaccel", XEiJ.musEdgeAccelerationOn ? "on" : "off");  //縁部加速
   915:     sgsCurrentMap.put ("mousespeed", String.valueOf (Z8530.scc0ScaleIndex));  //マウスカーソルの速度
   916:     sgsCurrentMap.put ("hostspixelunits", XEiJ.musHostsPixelUnitsOn ? "on" : "off");  //ホストの画素単位で動く
   917:     //MPU
   918:     //  機種とMPUの種類と動作周波数
   919:     //  機種の指定にMPUの種類と動作周波数が含まれているので必要のないものを省略する
   920:     switch (XEiJ.mdlModel) {
   921:     case XEiJ.MDL_EXPERT:
   922:       sgsCurrentMap.put ("model", "EXPERT");
   923:       sgsCurrentMap.put ("mpu", XEiJ.mpuCoreType == 0 ? "" : XEiJ.mpuCoreType == 3 ? "3" : "6");
   924:       sgsCurrentMap.put ("clock",
   925:                          XEiJ.mpuClockMHz == 10.0 ? "" :
   926:                          XEiJ.mpuClockMHz == 50.0 / 3.0 ? "XVI" :  //16.7MHz
   927:                          XEiJ.mpuClockMHz == 100.0 / 3.0 ? "Hybrid" :  //33.3MHz
   928:                          String.valueOf ((int) (XEiJ.mpuClockMHz + 0.5)));
   929:       break;
   930:     case XEiJ.MDL_SUPER:
   931:       sgsCurrentMap.put ("model", "SUPER");
   932:       sgsCurrentMap.put ("mpu", XEiJ.mpuCoreType == 0 ? "" : XEiJ.mpuCoreType == 3 ? "3" : "6");
   933:       sgsCurrentMap.put ("clock",
   934:                          XEiJ.mpuClockMHz == 10.0 ? "" :
   935:                          XEiJ.mpuClockMHz == 50.0 / 3.0 ? "XVI" :  //16.7MHz
   936:                          XEiJ.mpuClockMHz == 100.0 / 3.0 ? "Hybrid" :  //33.3MHz
   937:                          String.valueOf ((int) (XEiJ.mpuClockMHz + 0.5)));
   938:       break;
   939:     case XEiJ.MDL_XVI:
   940:       sgsCurrentMap.put ("model", "XVI");
   941:       sgsCurrentMap.put ("mpu", XEiJ.mpuCoreType == 0 ? "" : XEiJ.mpuCoreType == 3 ? "3" : "6");
   942:       sgsCurrentMap.put ("clock",
   943:                          XEiJ.mpuClockMHz == 50.0 / 3.0 ? "" :  //16.7MHz
   944:                          XEiJ.mpuClockMHz == 100.0 / 3.0 ? "Hybrid" :  //33.3MHz
   945:                          String.valueOf ((int) (XEiJ.mpuClockMHz + 0.5)));
   946:       break;
   947:     case XEiJ.MDL_COMPACT:
   948:       sgsCurrentMap.put ("model", "Compact");
   949:       sgsCurrentMap.put ("mpu", XEiJ.mpuCoreType == 0 ? "" : XEiJ.mpuCoreType == 3 ? "3" : "6");
   950:       sgsCurrentMap.put ("clock",
   951:                          XEiJ.mpuClockMHz == 50.0 / 3.0 ? "XVI" :  //16.7MHz
   952:                          XEiJ.mpuClockMHz == 25.0 ? "" :
   953:                          XEiJ.mpuClockMHz == 100.0 / 3.0 ? "Hybrid" :  //33.3MHz
   954:                          String.valueOf ((int) (XEiJ.mpuClockMHz + 0.5)));
   955:       break;
   956:     case XEiJ.MDL_HYBRID:
   957:       sgsCurrentMap.put ("model", "Hybrid");
   958:       sgsCurrentMap.put ("mpu", XEiJ.mpuCoreType == 0 ? "" : XEiJ.mpuCoreType == 3 ? "3" : "6");
   959:       sgsCurrentMap.put ("clock",
   960:                          XEiJ.mpuClockMHz == 50.0 / 3.0 ? "XVI" :  //16.7MHz
   961:                          XEiJ.mpuClockMHz == 100.0 / 3.0 ? "" :  //33.3MHz
   962:                          String.valueOf ((int) (XEiJ.mpuClockMHz + 0.5)));
   963:       break;
   964:     case XEiJ.MDL_X68030:
   965:       sgsCurrentMap.put ("model", "X68030");
   966:       sgsCurrentMap.put ("mpu", XEiJ.mpuCoreType == 0 ? "0" : XEiJ.mpuCoreType == 3 ? "" : "6");
   967:       sgsCurrentMap.put ("clock",
   968:                          XEiJ.mpuClockMHz == 50.0 / 3.0 ? "XVI" :  //16.7MHz
   969:                          XEiJ.mpuClockMHz == 25.0 ? "" :
   970:                          XEiJ.mpuClockMHz == 100.0 / 3.0 ? "Hybrid" :  //33.3MHz
   971:                          String.valueOf ((int) (XEiJ.mpuClockMHz + 0.5)));
   972:       break;
   973:     case XEiJ.MDL_060TURBO:
   974:       sgsCurrentMap.put ("model", "060turbo");
   975:       sgsCurrentMap.put ("mpu", XEiJ.mpuCoreType == 0 ? "0" : XEiJ.mpuCoreType == 3 ? "3" : "");
   976:       sgsCurrentMap.put ("clock",
   977:                          XEiJ.mpuClockMHz == 50.0 / 3.0 ? "XVI" :  //16.7MHz
   978:                          XEiJ.mpuClockMHz == 50.0 ? "" :
   979:                          XEiJ.mpuClockMHz == 100.0 / 3.0 ? "Hybrid" :  //33.3MHz
   980:                          String.valueOf ((int) (XEiJ.mpuClockMHz + 0.5)));
   981:       break;
   982:     default:
   983:       sgsCurrentMap.put ("model", "");
   984:       sgsCurrentMap.put ("mpu", XEiJ.mpuCoreType == 0 ? "0" : XEiJ.mpuCoreType == 3 ? "3" : "6");
   985:       sgsCurrentMap.put ("clock",
   986:                          XEiJ.mpuClockMHz == 50.0 / 3.0 ? "XVI" :  //16.7MHz
   987:                          XEiJ.mpuClockMHz == 100.0 / 3.0 ? "Hybrid" :  //33.3MHz
   988:                          String.valueOf ((int) (XEiJ.mpuClockMHz + 0.5)));
   989:     }
   990:     sgsCurrentMap.put ("mhz", String.valueOf (XEiJ.mpuArbFreqMHz));  //任意の周波数
   991:     sgsCurrentMap.put ("util", XEiJ.mpuUtilOn ? "on" : "off");  //任意の負荷率
   992:     sgsCurrentMap.put ("ratio", String.valueOf (XEiJ.mpuUtilRatio));  //負荷率
   993:     //FPU
   994:     sgsCurrentMap.put ("fpumode", String.valueOf (XEiJ.fpuMode));  //FPUモード
   995:     sgsCurrentMap.put ("fullspecfpu", XEiJ.fpuFullSpec ? "on" : "off");  //フルスペックFPU
   996:     //FPK
   997:     sgsCurrentMap.put ("fefunc", FEFunction.fpkOn ? "on" : "off");  //FEファンクション命令
   998:     sgsCurrentMap.put ("rejectfloat", FEFunction.fpkRejectFloatOn ? "on" : "off");  //FLOATn.Xを組み込まない
   999:     //BUS
  1000:     sgsCurrentMap.put ("highmemory", String.valueOf (XEiJ.busHighMemorySize >>> 20));  //X68030のハイメモリのサイズ(MB)
  1001:     if (XEiJ.prgIsLocal) {
  1002:       sgsCurrentMap.put ("highmemorysave", XEiJ.busHighMemorySaveOn ? "on" : "off");  //X68030のハイメモリの内容を保存する
  1003:       sgsCurrentMap.put ("highmemorydata", XEiJ.busHighMemorySaveOn ? ByteArray.byaEncodeBase64 (ByteArray.byaEncodeGzip (XEiJ.busHighMemoryArray, 0, Math.min (XEiJ.busHighMemoryArray.length, XEiJ.busHighMemorySize))) : "");  //X68030のハイメモリの内容
  1004:     }
  1005:     sgsCurrentMap.put ("localmemory", String.valueOf (XEiJ.busLocalMemorySize >>> 20));  //060turboのローカルメモリのサイズ(MB)
  1006:     if (XEiJ.prgIsLocal) {
  1007:       sgsCurrentMap.put ("localmemorysave", XEiJ.busLocalMemorySaveOn ? "on" : "off");  //060turboのローカルメモリの内容を保存する
  1008:       sgsCurrentMap.put ("localmemorydata", XEiJ.busLocalMemorySaveOn ? ByteArray.byaEncodeBase64 (ByteArray.byaEncodeGzip (XEiJ.busLocalMemoryArray, 0, Math.min (XEiJ.busLocalMemoryArray.length, XEiJ.busLocalMemorySize))) : "");  //060turboのローカルメモリの内容
  1009:     }
  1010:     sgsCurrentMap.put ("cutfc2pin", XEiJ.busRequestCutFC2Pin ? "on" : "off");  //FC2ピンをカットする(on/off)
  1011:     //MMR
  1012:     sgsCurrentMap.put ("memory", String.valueOf (MainMemory.mmrMemorySizeRequest >>> 20));  //メインメモリのサイズ
  1013:     if (MainMemory.MMR_SAVE) {
  1014:       if (XEiJ.prgIsLocal) {
  1015:         sgsCurrentMap.put ("memorysave", MainMemory.mmrMemorySaveOn ? "on" : "off");  //メインメモリの内容を保存する
  1016:         sgsCurrentMap.put ("memorydata", MainMemory.mmrMemorySaveOn ? ByteArray.byaEncodeBase64 (ByteArray.byaEncodeGzip (MainMemory.mmrM8, 0x00000000, MainMemory.mmrMemorySizeCurrent)) : "");  //メインメモリの内容
  1017:       }
  1018:     }
  1019:     //CRT
  1020:     if (CRTC.CRT_ENABLE_INTERMITTENT) {
  1021:       sgsCurrentMap.put ("intermittent", String.valueOf (CRTC.crtIntermittentInterval));  //間欠描画
  1022:     }
  1023:     if (CRTC.CRT_EXTENDED_GRAPHICS) {
  1024:       sgsCurrentMap.put ("extendedgraphics", CRTC.crtExtendedGraphicsRequest ? "on" : "off");  //拡張グラフィックス画面
  1025:     }
  1026:     //SND
  1027:     sgsCurrentMap.put ("sound", SoundSource.sndPlayOn ? "on" : "off");  //音声出力
  1028:     sgsCurrentMap.put ("volume", String.valueOf (SoundSource.sndVolume));  //ボリューム
  1029:     sgsCurrentMap.put ("soundinterpolation",
  1030:                        SoundSource.sndRateConverter == (SoundSource.SND_CHANNELS == 1 ? SoundSource.SNDRateConverter.THINNING_MONO : SoundSource.SNDRateConverter.THINNING_STEREO) ? "thinning" :  //間引き
  1031:                        SoundSource.sndRateConverter == (SoundSource.SND_CHANNELS == 1 ? SoundSource.SNDRateConverter.LINEAR_MONO : SoundSource.SNDRateConverter.LINEAR_STEREO) ? "linear" :  //線形補間
  1032:                        SoundSource.sndRateConverter == SoundSource.SNDRateConverter.CONSTANT_AREA_STEREO_48000 ? "constant-area" :  //区分定数面積補間
  1033:                        SoundSource.sndRateConverter == SoundSource.SNDRateConverter.LINEAR_AREA_STEREO_48000 ? "linear-area" :  //線形面積補間
  1034:                        "linear");  //線形補間
  1035:     //OPM
  1036:     sgsCurrentMap.put ("opmoutput", YM2151.opmOutputMask != 0 ? "on" : "off");  //OPM出力
  1037:     //PCM
  1038:     sgsCurrentMap.put ("pcmoutput", ADPCM.pcmOutputOn ? "on" : "off");  //PCM出力
  1039:     sgsCurrentMap.put ("pcminterpolation",
  1040:                        ADPCM.pcmInterpolationAlgorithm == ADPCM.PCM_INTERPOLATION_CONSTANT ? "constant" :  //区分定数補間
  1041:                        ADPCM.pcmInterpolationAlgorithm == ADPCM.PCM_INTERPOLATION_LINEAR ? "linear" :  //線形補間
  1042:                        ADPCM.pcmInterpolationAlgorithm == ADPCM.PCM_INTERPOLATION_HERMITE ? "hermite" :  //エルミート補間
  1043:                        "linear");  //線形補間
  1044:     sgsCurrentMap.put ("pcmoscfreq", String.valueOf (ADPCM.pcmOSCFreqRequest));  //原発振周波数
  1045:     //FDC
  1046:     //  FDDのイメージファイル
  1047:     for (int u = 0; u < FDC.FDC_MAX_UNITS; u++) {
  1048:       AbstractUnit unit = FDC.fdcUnitArray[u];
  1049:       sgsCurrentMap.put ("fd" + u,
  1050:                          unit.abuConnected && unit.abuInserted ? unit.abuWriteProtected ? unit.abuPath + ":R" : unit.abuPath : "");
  1051:     }
  1052:     //HDC
  1053:     //  SASI HDDのイメージファイル
  1054:     for (int u = 0; u < 16; u++) {
  1055:       AbstractUnit unit = HDC.hdcUnitArray[u];
  1056:       sgsCurrentMap.put ("hd" + u,
  1057:                          unit.abuConnected && unit.abuInserted ? unit.abuWriteProtected ? unit.abuPath + ":R" : unit.abuPath : "");
  1058:     }
  1059:     //SPC
  1060:     //  SCSI HDDのイメージファイル
  1061:     for (int u = 0; u < 16; u++) {
  1062:       AbstractUnit unit = SPC.spcUnitArray[u];
  1063:       sgsCurrentMap.put ("sc" + u,
  1064:                          unit.abuConnected && unit.abuInserted ? unit.abuWriteProtected ? unit.abuPath + ":R" : unit.abuPath : "");
  1065:     }
  1066:     //PPI
  1067:     //  ジョイスティック
  1068:     sgsCurrentMap.put ("joykey", XEiJ.ppiJoyKey ? "on" : "off");
  1069:     sgsCurrentMap.put ("joyauto", XEiJ.ppiJoyAuto ? "on" : "off");
  1070:     sgsCurrentMap.put ("joyblock", XEiJ.ppiJoyBlock ? "on" : "off");
  1071:     sgsCurrentMap.put ("joymap", XEiJ.ppiMakeParam ());
  1072:     //HFS
  1073:     //  ホストのディレクトリ名
  1074:     for (int u = 0; u < HFS.HFS_MAX_UNITS; u++) {
  1075:       AbstractUnit unit = HFS.hfsUnitArray[u];
  1076:       sgsCurrentMap.put ("hf" + u,
  1077:                          unit.abuConnected && unit.abuInserted ? unit.abuWriteProtected ? unit.abuPath + ":R" : unit.abuPath : "");
  1078:     }
  1079:     //EXS
  1080:     sgsCurrentMap.put ("scsiexrom", SPC.spcSCSIEXROM);  //拡張SCSI ROMイメージファイル名
  1081:     sgsCurrentMap.put ("scsiex", SPC.spcSCSIEXRequest ? "on" : "off");  //拡張SCSIポートの有無
  1082:     //SMR
  1083:     sgsCurrentMap.put ("sram", XEiJ.smrSramName);  //SRAMイメージファイル名
  1084:     sgsCurrentMap.put ("sramdata", XEiJ.smrMakeSramData ());  //SRAMの内容
  1085:     sgsCurrentMap.put ("sramsize", String.valueOf (XEiJ.smrSramSizeRequest >> 10));  //SRAMの容量
  1086:     sgsCurrentMap.put ("keydly", String.valueOf (XEiJ.smrRepeatDelay));  //リピートディレイ
  1087:     sgsCurrentMap.put ("keyrep", String.valueOf (XEiJ.smrRepeatInterval));  //リピートインターバル
  1088:     //  起動デバイス
  1089:     sgsCurrentMap.put ("boot",
  1090:                        XEiJ.smrBootDevice == -1 ? "" :
  1091:                        XEiJ.smrBootDevice == 0x0000 ? "std" :
  1092:                        (XEiJ.smrBootDevice & 0xf000) == 0x9000 ? "fd" + (XEiJ.smrBootDevice >> 8 & 3) :
  1093:                        (XEiJ.smrBootDevice & 0xf000) == 0x8000 ? "hd" + (XEiJ.smrBootDevice >> 8 & 15) :
  1094:                        XEiJ.smrBootDevice == 0xa000 ?
  1095:                        (XEiJ.smrBootROM & ~(7 << 2)) == SPC.SPC_HANDLE_EX ? "sc" + (XEiJ.smrBootROM >> 2 & 7) :
  1096:                        XEiJ.smrBootROM == HFS.HFS_BOOT_HANDLE ? "hf" + HFS.hfsBootUnit :
  1097:                        String.format ("rom$%08X", XEiJ.smrBootROM) :
  1098:                        XEiJ.smrBootDevice == 0xb000 ? String.format ("ram$%08X", XEiJ.smrBootRAM) :
  1099:                        "");
  1100:     //ROM
  1101:     sgsCurrentMap.put ("rom", XEiJ.romROMName);
  1102:     sgsCurrentMap.put ("iplrom", XEiJ.romIPLROMName);
  1103:     sgsCurrentMap.put ("romdb", XEiJ.romROMDBOn ? "on" : "off");
  1104:     sgsCurrentMap.put ("scsiinrom", XEiJ.romSCSIINROMName);
  1105:     sgsCurrentMap.put ("rom30", XEiJ.romROM30Name);
  1106:     //FNT
  1107:     sgsCurrentMap.put ("cgrom", FontEditor.fntCGROMName);
  1108:     sgsCurrentMap.put ("omusubi", FontEditor.fntOmusubiOn ? "on" : "off");
  1109:     //PRN
  1110:     sgsCurrentMap.put ("prnauto", PrinterPort.prnAutosaveOn ? "on" : "off");
  1111:     sgsCurrentMap.put ("prnpath", PrinterPort.prnSavePath);
  1112: 
  1113:     //ウインドウの位置とサイズと状態
  1114:     for (String key : SGS_FRAME_KEYS) {
  1115:       //ウインドウの位置とサイズ
  1116:       Rectangle bounds = RestorableFrame.rfmGetBounds (key);  //位置とサイズ
  1117:       sgsCurrentMap.put (key + "rect",
  1118:                          new StringBuilder ().
  1119:                          append (bounds.x).append (',').
  1120:                          append (bounds.y).append (',').
  1121:                          append (bounds.width).append (',').
  1122:                          append (bounds.height).toString ());
  1123:       //ウインドウの状態
  1124:       int state = RestorableFrame.rfmGetState (key);  //状態
  1125:       sgsCurrentMap.put (key + "stat",
  1126:                          (state & Frame.ICONIFIED) == Frame.ICONIFIED ? "iconified" :  //アイコン化されている
  1127:                          (state & Frame.MAXIMIZED_BOTH) == Frame.MAXIMIZED_BOTH ? "maximized" :  //最大化されている
  1128:                          (state & Frame.MAXIMIZED_BOTH) == Frame.MAXIMIZED_HORIZ ? "h-maximized" :  //水平方向だけ最大化されている
  1129:                          (state & Frame.MAXIMIZED_BOTH) == Frame.MAXIMIZED_VERT ? "v-maximized" :  //垂直方向だけ最大化されている
  1130:                          "normal");  //通常表示
  1131:       //ウインドウが開いているかどうか
  1132:       sgsCurrentMap.put (key + "open", RestorableFrame.rfmGetOpened (key) ? "on" : "off");
  1133:     }
  1134: 
  1135:     //保存する
  1136:     sgsInterface.sgiSave (sgsEncodeRootMap ());
  1137: 
  1138:   }  //sgsSaveSettings()
  1139: 
  1140:   //sgsSaveSettingsAs ()
  1141:   //  「設定に名前を付けて保存」
  1142:   public static void sgsSaveSettingsAs () {
  1143:     sgsMakeNameArray ();
  1144:     if (sgsSaveSettingsAsFrame == null) {
  1145:       sgsMakeSaveSettingsAsFrame ();
  1146:     }
  1147:     sgsSaveSettingsAsScrollList.setTexts (sgsNameArray);
  1148:     sgsSaveSettingsAsScrollList.setEnabled (sgsNameArray.length != 0);  //名前が付いている設定がなければリストは動作しない
  1149:     sgsSaveSettingsAsTextField.setText ("");  //新しい設定の名前の初期値は""
  1150:     sgsSaveSettingsAsFrame.setVisible (true);
  1151:   }  //sgsSaveSettingsAs()
  1152: 
  1153:   //sgsRemoveNamedSettings ()
  1154:   //  「名前を付けた設定を削除」
  1155:   public static void sgsRemoveNamedSettings () {
  1156:     sgsMakeNameArray ();
  1157:     if (sgsRemoveNamedSettingsFrame == null) {
  1158:       sgsMakeRemoveNamedSettingsFrame ();
  1159:     }
  1160:     sgsRemoveNamedSettingsScrollList.setTexts (sgsNameArray);
  1161:     sgsRemoveNamedSettingsScrollList.setEnabled (sgsNameArray.length != 0);  //名前が付いている設定がなければリストは動作しない
  1162:     sgsRemoveNamedSettingsRemoveButton.setEnabled (sgsNameArray.length != 0);  //名前が付いている設定がなければ削除ボタンは動作しない
  1163:     sgsRemoveNamedSettingsFrame.setVisible (true);
  1164:   }  //sgsRemoveNamedSettings()
  1165: 
  1166:   //sgsMakeSaveSettingsAsFrame ()
  1167:   //  「設定に名前を付けて保存」ウインドウを作る
  1168:   public static void sgsMakeSaveSettingsAsFrame () {
  1169:     //アクションリスナー
  1170:     ActionListener listener = new ActionListener () {
  1171:       @Override public void actionPerformed (ActionEvent ae) {
  1172:         switch (ae.getActionCommand ()) {
  1173:         case "Save":
  1174:           {
  1175:             String name = sgsSaveSettingsAsTextField.getText ();  //新しい設定名
  1176:             if (name.length () != 0 &&  //新しい設定名が""ではなくて
  1177:                 (!sgsRootMap.containsKey (name) ||  //新しい設定名が存在しないか
  1178:                  JOptionPane.showConfirmDialog (
  1179:                    XEiJ.prgIsApplet ? null : XEiJ.frmFrame,
  1180:                    Multilingual.mlnJapanese ? "設定 " + name + " を上書きしますか?" : "Do you want to overwrite settings named " + name + " ?",
  1181:                    Multilingual.mlnJapanese ? "設定の上書きの確認" : "Confirmation of overwriting settings",
  1182:                    JOptionPane.YES_NO_OPTION,
  1183:                    JOptionPane.PLAIN_MESSAGE) == JOptionPane.YES_OPTION)) {  //上書きが許可されたとき
  1184:               HashMap<String,String> map = new HashMap<String,String> (sgsCurrentMap);  //現在の設定をコピーする
  1185:               map.put ("_", name);  //設定名
  1186:               sgsRootMap.put (name, map);  //設定を上書きする
  1187:               sgsSaveAllSettings ();  //保存する
  1188:               sgsSaveSettingsAsFrame.setVisible (false);  //ウインドウを閉じる
  1189:             }
  1190:             //新しい設定名が""または新しい設定名が存在して上書きが許可されなかったときはウインドウを閉じない
  1191:           }
  1192:           break;
  1193:         case "Cancel":
  1194:           sgsSaveSettingsAsFrame.setVisible (false);  //ウインドウを閉じる
  1195:           break;
  1196:         }
  1197:       }
  1198:     };
  1199:     //ウインドウ
  1200:     sgsSaveSettingsAsFrame = Multilingual.mlnTitle (
  1201:       ComponentFactory.createRestorableSubFrame (
  1202:         SGS_GSA_FRAME_KEY,
  1203:         "Save Settings As",
  1204:         null,
  1205:         ComponentFactory.createBorderPanel (
  1206:           0, 0,
  1207:           ComponentFactory.createVerticalBox (
  1208:             Box.createVerticalStrut (12),
  1209:             ComponentFactory.createHorizontalBox (
  1210:               Box.createHorizontalStrut (12),
  1211:               Multilingual.mlnText (ComponentFactory.createLabel ("Names of existing settings"), "ja", "保存されている設定の名前"),
  1212:               Box.createHorizontalGlue ()
  1213:               ),
  1214:             ComponentFactory.createHorizontalBox (
  1215:               Box.createHorizontalStrut (12),
  1216:               sgsSaveSettingsAsScrollList = ComponentFactory.createScrollList (new String[0], 5, 0, new ListSelectionListener () {
  1217:                 @Override public void valueChanged (ListSelectionEvent lse) {
  1218:                   if (sgsNameArray != null && sgsSaveSettingsAsTextField != null) {
  1219:                     int index = sgsSaveSettingsAsScrollList.getSelectedIndex ();  //lse.getFirstIndex()は変化した項目のインデックスの最小値であって現在選択されているインデックスではない
  1220:                     if (0 <= index && index < sgsNameArray.length) {
  1221:                       sgsSaveSettingsAsTextField.setText (sgsNameArray[index]);
  1222:                     }
  1223:                   }
  1224:                 }
  1225:               }),
  1226:               Box.createHorizontalStrut (12)
  1227:               ),
  1228:             Box.createVerticalStrut (12),
  1229:             ComponentFactory.createHorizontalBox (
  1230:               Box.createHorizontalStrut (12),
  1231:               Multilingual.mlnText (ComponentFactory.createLabel ("New name"), "ja", "新しい名前"),
  1232:               Box.createHorizontalGlue ()
  1233:               ),
  1234:             ComponentFactory.createHorizontalBox (
  1235:               Box.createHorizontalStrut (12),
  1236:               sgsSaveSettingsAsTextField = ComponentFactory.setHorizontalAlignment (
  1237:                 ComponentFactory.createTextField ("", 20),
  1238:                 JTextField.LEFT),
  1239:               Box.createHorizontalStrut (12)
  1240:               ),
  1241:             Box.createVerticalStrut (12),
  1242:             ComponentFactory.createHorizontalBox (
  1243:               Box.createHorizontalStrut (12),
  1244:               Box.createHorizontalGlue (),
  1245:               Multilingual.mlnText (ComponentFactory.createButton ("Save", listener), "ja", "保存する"),
  1246:               Box.createHorizontalStrut (12),
  1247:               Multilingual.mlnText (ComponentFactory.createButton ("Cancel", listener), "ja", "キャンセル"),
  1248:               Box.createHorizontalStrut (12)
  1249:               ),
  1250:             Box.createVerticalStrut (12)
  1251:             )
  1252:           )
  1253:         ),
  1254:       "ja", "設定に名前を付けて保存");
  1255:   }  //sgsMakeSaveSettingsAsFrame()
  1256: 
  1257:   //sgsMakeRemoveNamedSettingsFrame ()
  1258:   //  「名前を付けた設定を削除」ウインドウを作る
  1259:   public static void sgsMakeRemoveNamedSettingsFrame () {
  1260:     //アクションリスナー
  1261:     ActionListener listener = new ActionListener () {
  1262:       @Override public void actionPerformed (ActionEvent ae) {
  1263:         switch (ae.getActionCommand ()) {
  1264:         case "Remove":
  1265:           {
  1266:             int index = sgsRemoveNamedSettingsScrollList.getSelectedIndex ();
  1267:             if (0 <= index && index < sgsNameArray.length) {  //選択されている
  1268:               String name = sgsNameArray[index];
  1269:               if (name.length () != 0 &&  //削除する設定名が""ではなくて
  1270:                   sgsRootMap.containsKey (name) &&  //削除する設定が存在して
  1271:                   JOptionPane.showConfirmDialog (
  1272:                     XEiJ.prgIsApplet ? null : XEiJ.frmFrame,
  1273:                     Multilingual.mlnJapanese ? "設定 " + name + " を削除しますか?" : "Do you want to remove settings named " + name + " ?",
  1274:                     Multilingual.mlnJapanese ? "設定の削除の確認" : "Confirmation of removing settings",
  1275:                     JOptionPane.YES_NO_OPTION,
  1276:                     JOptionPane.PLAIN_MESSAGE) == JOptionPane.YES_OPTION) {  //削除が許可されたとき
  1277:                 sgsRootMap.remove (name);  //設定を削除する
  1278:                 sgsSaveAllSettings ();  //保存する
  1279:                 sgsRemoveNamedSettingsFrame.setVisible (false);  //ウインドウを閉じる
  1280:               }
  1281:               //削除する設定名が""または削除する設定名が存在して上書きが許可されなかったときはダイアログを閉じない
  1282:             }
  1283:             //選択されていないか範囲外のときはウインドウを閉じない
  1284:           }
  1285:           break;
  1286:         case "Cancel":
  1287:           sgsRemoveNamedSettingsFrame.setVisible (false);  //ウインドウを閉じる
  1288:           break;
  1289:         }
  1290:       }
  1291:     };
  1292:     //ウインドウ
  1293:     sgsRemoveNamedSettingsFrame = Multilingual.mlnTitle (
  1294:       ComponentFactory.createRestorableSubFrame (
  1295:         SGS_GRS_FRAME_KEY,
  1296:         "Remove Named Settings",
  1297:         null,
  1298:         ComponentFactory.createBorderPanel (
  1299:           0, 0,
  1300:           ComponentFactory.createVerticalBox (
  1301:             Box.createVerticalStrut (12),
  1302:             ComponentFactory.createHorizontalBox (
  1303:               Box.createHorizontalStrut (12),
  1304:               Multilingual.mlnText (ComponentFactory.createLabel ("Names of existing settings"), "ja", "保存されている設定の名前"),
  1305:               Box.createHorizontalGlue ()
  1306:               ),
  1307:             ComponentFactory.createHorizontalBox (
  1308:               Box.createHorizontalStrut (12),
  1309:               sgsRemoveNamedSettingsScrollList = ComponentFactory.createScrollList (new String[0], 5, 0, null),
  1310:               Box.createHorizontalStrut (12)
  1311:               ),
  1312:             Box.createVerticalStrut (12),
  1313:             ComponentFactory.createHorizontalBox (
  1314:               Box.createHorizontalStrut (12),
  1315:               Box.createHorizontalGlue (),
  1316:               sgsRemoveNamedSettingsRemoveButton = Multilingual.mlnText (ComponentFactory.createButton ("Remove", listener), "ja", "削除する"),
  1317:               Box.createHorizontalStrut (12),
  1318:               Multilingual.mlnText (ComponentFactory.createButton ("Cancel", listener), "ja", "キャンセル"),
  1319:               Box.createHorizontalStrut (12)
  1320:               ),
  1321:             Box.createVerticalStrut (12)
  1322:             )
  1323:           )
  1324:         ),
  1325:       "ja", "名前を付けた設定を削除");
  1326:   }  //sgsMakeRemoveNamedSettingsFrame()
  1327: 
  1328:   //sgsMakeNameArray ()
  1329:   //  設定名の配列を作る
  1330:   public static void sgsMakeNameArray () {
  1331:     ArrayList<String> nameList = new ArrayList<String> (sgsRootMap.keySet ());  //設定名のリスト
  1332:     nameList.sort (DictionaryComparator);  //設定名をソートする。設定名が""の現在の設定が先頭に来る
  1333:     nameList.remove (0);  //先頭にある現在の設定の設定名""を取り除く
  1334:     sgsNameArray = nameList.toArray (new String[0]);  //現在の設定を除いてソートされた設定名の配列
  1335:   }  //sgsMakeNameArray()
  1336: 
  1337:   //sgsRemoveAllSettings ()
  1338:   //  すべての設定を削除する
  1339:   public static void sgsRemoveAllSettings () {
  1340:     if (JOptionPane.showConfirmDialog (
  1341:       XEiJ.prgIsApplet ? null : XEiJ.frmFrame,
  1342:       Multilingual.mlnJapanese ? "すべての設定を削除しますか?" : "Do you want to remove all settings?",
  1343:       Multilingual.mlnJapanese ? "確認" : "Confirmation",
  1344:       JOptionPane.YES_NO_OPTION) == JOptionPane.YES_NO_OPTION) {  //Yes
  1345:       //すべての設定を削除する
  1346:       sgsInterface.sgiDelete ();
  1347:       //終了時に設定を保存をOFFにする
  1348:       sgsSaveOnExitCheckBox.setSelected (false);
  1349:       sgsSaveOnExit = false;
  1350:     }
  1351:   }  //sgsRemoveAllSettings()
  1352: 
  1353:   //sgsDecodeRootMap (text)
  1354:   //  テキストをsgsRootMapに変換する
  1355:   public static void sgsDecodeRootMap (String text) {
  1356:     sgsRootMap.clear ();  //すべての設定を消す
  1357:     sgsCurrentMap.clear ();  //古いマップを消しておく
  1358:     sgsCurrentMap = new HashMap<String,String> (sgsStartMap);  //開始時の設定を現在の設定にコピーする
  1359:     sgsCurrentMap.put ("_", "");  //設定名を加える
  1360:     sgsRootMap.put ("", sgsCurrentMap);  //新しいマップを繋ぎ直す
  1361:     HashMap<String,String> map = sgsCurrentMap;  //現在変換中の設定は現在の設定
  1362:     for (String line : text.split ("\n")) {
  1363:       line = line.trim ();  //キーの前の空白と値の後の空白を取り除く
  1364:       if (line.length () == 0 ||  //空行
  1365:           line.startsWith ("#")) {  //注釈
  1366:         continue;
  1367:       }
  1368:       int i = line.indexOf ('=');
  1369:       if (i < 0) {  //'='がない
  1370:         continue;
  1371:       }
  1372:       String key = line.substring (0, i).trim ().toLowerCase ();  //キー。後('='の前)の空白を取り除いて小文字化する
  1373:       String value = line.substring (i + 1).trim ();  //値。前('='の後)の空白を取り除く
  1374:       if (key.equals ("_")) {  //設定名。新しい設定の最初の行
  1375:         if (sgsRootMap.containsKey (value)) {  //同じ設定名が2回出てきたとき
  1376:           if (false) {
  1377:             map = null;  //新しい設定名が指定されるまで読み飛ばす(最初に書いた設定が残る)
  1378:           } else {
  1379:             map = sgsRootMap.get (value);  //既存の設定に上書きする(最後に書いた設定が残る)
  1380:           }
  1381:         } else {  //新しい設定
  1382:           map = new HashMap<String,String> (sgsStartMap);  //開始時の設定をコピーする
  1383:           map.put (key, value);  //sgsPutParameterは設定名のキー"_"を受け付けないことに注意
  1384:           sgsRootMap.put (value, map);
  1385:         }
  1386:         continue;
  1387:       }
  1388:       if (map == null) {  //新しい設定名が指定されるまで読み飛ばす
  1389:         continue;
  1390:       }
  1391:       sgsPutParameter (map, key, value);
  1392:     }  //for line
  1393:   }  //sgsDecodeRootMap()
  1394: 
  1395:   //text = sgsEncodeRootMap ()
  1396:   //  sgsRootMapをテキストに変換する
  1397:   public static String sgsEncodeRootMap () {
  1398:     StringBuilder sb = new StringBuilder ();
  1399:     String[] nameArray = sgsRootMap.keySet ().toArray (new String[0]);  //設定名の配列
  1400:     Arrays.sort (nameArray, DictionaryComparator);  //設定名をソートする。設定名が""の現在の設定が先頭に来る
  1401:     for (String name : nameArray) {
  1402:       HashMap<String,String> map = sgsRootMap.get (name);  //個々の設定
  1403:       if (map != sgsCurrentMap) {  //(先頭の)現在の設定でないとき
  1404:         sb.append ('\n');  //1行空ける
  1405:       }
  1406:       String[] keyArray = map.keySet ().toArray (new String[0]);  //キーの配列
  1407:       Arrays.sort (keyArray, DictionaryComparator);  //キーをソートする。設定名以外のキーはすべて英小文字で始まるので設定名のキー"_"が先頭に来る
  1408:       for (String key : keyArray) {
  1409:         String value = map.get (key);
  1410:         if (!(map == sgsCurrentMap && key.equals ("_")) &&  //現在の設定の設定名でない
  1411:             !key.equals ("config") &&  //キー"config"は設定ファイルに出力しない
  1412:             !value.equals (sgsStartMap.get (key))) {  //開始時の設定にないか、開始時の設定と異なる
  1413:           sb.append (key).append ('=').append (value).append ('\n');
  1414:         }
  1415:       }
  1416:     }
  1417:     return sb.toString ();
  1418:   }  //sgsEncodeRootMap()
  1419: 
  1420:   //map = sgsGetAppletParameters ()
  1421:   //  アプレットの<object><param>~</param></object>で指定されたパラメータを読み取る
  1422:   public static HashMap<String,String> sgsGetAppletParameters () {
  1423:     HashMap<String,String> map = new HashMap<String,String> ();
  1424:     int fdNumber = 0;
  1425:     int hdNumber = 0;
  1426:     int scNumber = 0;
  1427:     for (String key : sgsDefaultMap.keySet ()) {  //指定できる名前をすべて試す
  1428:       String value = XEiJApplet.appApplet.getParameter (key);
  1429:       if (value != null) {  //指定されている
  1430:         if (key.equals ("boot") && !SGS_BOOT_DEVICE_PATTERN.matcher (value).matches ()) {  //キーがbootだが値が起動デバイス名でない
  1431:           String valueWithoutColonR = value.toUpperCase ().endsWith (":R") ? value.substring (0, value.length () - 2) : value;  //末尾の":R"を取り除いた部分
  1432:           int length = XEiJ.ismLength (valueWithoutColonR, HDMedia.HDM_MAX_BYTES_PER_DISK + 1);  //ファイルサイズ。40MBのSASI HDのサイズまで区別できればよい
  1433:           if (length >= 0) {  //ファイルがある
  1434:             key = (FDMedia.fdmPathToMedia (valueWithoutColonR, null) != null ? "fd" + fdNumber++ :  //FD
  1435:                    HDMedia.hdmLengthToMedia (length) != null ? "hd" + hdNumber++ :  //SASI HD
  1436:                    "sc" + scNumber++);  //それ以外はSCSI ハードディスク/CD-ROM
  1437:             sgsPutParameter (map, "boot", key);  //起動デバイスを設定する
  1438:           } else {  //ファイルがない
  1439:             //!!! エラー
  1440:             continue;
  1441:           }
  1442:         }
  1443:         sgsPutParameter (map, key, value);  //パラメータを設定する
  1444:       }
  1445:     }
  1446:     return map;
  1447:   }  //sgsGetAppletParameters()
  1448: 
  1449:   //map = sgsGetArgumentParameters ()
  1450:   //  ローカルのコマンドラインまたは*.jnlpファイルの<application-desc><argument>~</argument></application-desc>で指定されたパラメータを読み取る
  1451:   public static HashMap<String,String> sgsGetArgumentParameters () {
  1452:     HashMap<String,String> map = new HashMap<String,String> ();
  1453:     int fdNumber = 0;
  1454:     int hdNumber = 0;
  1455:     int scNumber = 0;
  1456:     int hfNumber = 0;
  1457:     for (int i = 0; i < XEiJ.prgArgs.length; i++) {
  1458:       String key = null;  //キー
  1459:       String value = XEiJ.prgArgs[i];  //引数。nullではないはず
  1460:     arg:
  1461:       {
  1462:         boolean boot = false;  //true=valueは-bootの値
  1463:         if (value.startsWith ("-")) {  //引数が"-"で始まっている
  1464:           //!!! 値が必要なものと必要でないものを区別したい
  1465:           int k = value.indexOf ('=', 1);
  1466:           if (k >= 0) {  //引数が"-"で始まっていて2文字目以降に"="がある
  1467:             key = value.substring (1, k);  //"-"の後ろから"="の手前まではキー
  1468:             value = value.substring (k + 1);  //"="の後ろは値
  1469:           } else {  //引数が"-"で始まっていて2文字目以降に"="がない
  1470:             //!!! "-"で始まる引数はすべてキーとみなされるので"-キー 値"の形では値に負の数値を書くことはできない
  1471:             key = value.substring (1);  //"-"の後ろはキー
  1472:             value = (i + 1 < XEiJ.prgArgs.length && !XEiJ.prgArgs[i + 1].startsWith ("-") ?  //次の引数があって次の引数が"-"で始まっていない
  1473:                      XEiJ.prgArgs[++i]  //次の引数は値
  1474:                      :  //次の引数がないまたは次の引数が"-"で始まっている
  1475:                      "1");  //値は"1"
  1476:           }
  1477:           if (!key.equalsIgnoreCase ("boot")) {  //-bootではない
  1478:             break arg;
  1479:           }
  1480:           boot = true;
  1481:         }
  1482:         //引数が"-"で始まっていないまたは-bootの値
  1483:         if (SGS_BOOT_DEVICE_PATTERN.matcher (value).matches ()) {  //起動デバイス名のとき
  1484:           //ファイルやディレクトリを探さず起動デバイスだけ設定する
  1485:           key = "boot";
  1486:           break arg;
  1487:         }
  1488:         String valueWithoutColonR = value.toUpperCase ().endsWith (":R") ? value.substring (0, value.length () - 2) : value;  //末尾の":R"を取り除いた部分
  1489:         int length = XEiJ.ismLength (valueWithoutColonR, HDMedia.HDM_MAX_BYTES_PER_DISK + 1);  //ファイルサイズ。40MBのSASI HDのサイズまで区別できればよい
  1490:         if (length >= 0) {  //ファイルがある
  1491:           key = (FDMedia.fdmPathToMedia (valueWithoutColonR, null) != null ? "fd" + fdNumber++ :  //FD
  1492:                  HDMedia.hdmLengthToMedia (length) != null ? "hd" + hdNumber++ :  //SASI HD
  1493:                  "sc" + scNumber++);  //それ以外はSCSI ハードディスク/CD-ROM
  1494:         } else if (XEiJ.prgIsLocal &&  //ローカルのとき
  1495:                    new File (valueWithoutColonR).isDirectory ()) {  //ディレクトリがある
  1496:           key = "hf" + hfNumber++;
  1497:         } else {  //ファイルがなくディレクトリもない
  1498:           //!!! エラー
  1499:           continue;
  1500:         }
  1501:         if (boot) {  //-bootの値のとき
  1502:           sgsPutParameter (map, "boot", key);  //起動デバイスを設定する
  1503:         }
  1504:       }  //arg
  1505:       if (XEiJ.prgIsLocal) {  //ローカルのとき
  1506:         //ローカルのときだけ指定できるオプション
  1507:         switch (key) {
  1508:         case "ini":
  1509:           sgsLocalIniFile = new File (value).getAbsoluteFile ();
  1510:           sgsLocalIniPath = sgsLocalIniFile.getPath ();
  1511:           break;
  1512:         case "opmtest":
  1513:           sgsOpmtestOn = true;
  1514:           break;
  1515:         case "saveicon":
  1516:           sgsSaveiconValue = value;
  1517:           break;
  1518:         case "irbbench":
  1519:           sgsIrbbenchValue = value;
  1520:           break;
  1521:         default:
  1522:           sgsPutParameter (map, key, value);  //パラメータを設定する
  1523:         }
  1524:       } else {  //ローカルでないとき
  1525:         sgsPutParameter (map, key, value);  //パラメータを設定する
  1526:       }  //if XEiJ.prgIsLocal
  1527:     }
  1528:     return map;
  1529:   }  //sgsGetArgumentParameters()
  1530: 
  1531:   //sgsPutParameter (map, key, value)
  1532:   //  マップにパラメータを追加する
  1533:   //  デフォルトの設定sgsDefaultMapにないパラメータは無視される。設定名のキー"_"を受け付けないことに注意
  1534:   //  デフォルトの値が"off"または"on"のパラメータの値は"0","no","off"を指定すると"off"、それ以外は"on"に読み替えられる
  1535:   public static void sgsPutParameter (HashMap<String,String> map, String key, String value) {
  1536:     if (sgsDefaultMap.containsKey (key)) {  //設定できるパラメータ
  1537:       String defaultValue = sgsDefaultMap.get (key);  //デフォルトの値
  1538:       if (defaultValue.equals ("off") || defaultValue.equals ("on")) {  //デフォルトの値が"off"または"on"のとき
  1539:         value = (value.equals ("0") ||
  1540:                  value.equalsIgnoreCase ("no") ||
  1541:                  value.equalsIgnoreCase ("off") ? "off" : "on");  //"0","no","off"を"off"にそれ以外を"on"に読み替える
  1542:       }
  1543:       map.put (key, value);  //マップに追加する
  1544:     }
  1545:   }  //sgsPutParameter(HashMap<String,String>,String,String)
  1546: 
  1547: 
  1548: 
  1549:   //================================================================================
  1550:   //$$SGI 設定インタフェイス
  1551:   //  起動方法に応じてパラメータの読み取りと設定の入出力を行う
  1552:   public interface SGSInterface {
  1553: 
  1554:     //map = gate.sgiGetParameters ()
  1555:     //  パラメータを読み取る
  1556:     public HashMap<String,String> sgiGetParameters ();
  1557: 
  1558:     //text = gate.sgiLoad ()
  1559:     //  設定ファイルを読み込む
  1560:     public String sgiLoad ();
  1561: 
  1562:     //gate.sgiSave ()
  1563:     //  設定ファイルに書き出す
  1564:     public void sgiSave (String text);
  1565: 
  1566:     //gate.sgiDelete ()
  1567:     //  設定ファイルを削除する
  1568:     public void sgiDelete ();
  1569: 
  1570:   }
  1571: 
  1572: 
  1573: 
  1574:   //================================================================================
  1575:   //$$SGA アプレットの設定
  1576:   //  アプレットのときパラメータの読み取りと設定の入出力を行う
  1577:   //  アプレットの<object><param>~</param></object>で指定されたパラメータを読み取る
  1578:   //  localStorageに設定を保存する
  1579:   //    localStorageはCookieと違って任意の文字列を保存できる。Percent-Encodingやbase64でエンコードする必要はない
  1580:   //  ドキュメントベース毎にそれぞれ設定ファイルを作る
  1581:   public static class SGSApplet implements SGSInterface {
  1582: 
  1583:     private String sgaItemName;
  1584: 
  1585:     //コンストラクタ
  1586:     private SGSApplet () {
  1587:       sgaItemName = XEiJApplet.appApplet.getDocumentBase ().toString () + "/" + SGS_INI;
  1588:     }  //new SGSApplet()
  1589: 
  1590:     //map = gate.sgiGetParameters ()
  1591:     //  パラメータを読み取る
  1592:     @Override public HashMap<String,String> sgiGetParameters () {
  1593:       return sgsGetAppletParameters ();
  1594:     }  //sgiGetParameters()
  1595: 
  1596:     //text = gate.sgiLoad ()
  1597:     //  設定ファイルを読み込む
  1598:     @Override public String sgiLoad () {
  1599:       JSObject localStorage = XEiJApplet.appGetJSObject (XEiJApplet.appWindow, "localStorage");  //window.localStorage
  1600:       if (localStorage != null) {
  1601:         String value = XEiJApplet.appCallString (localStorage, "getItem", sgaItemName);
  1602:         if (value != null) {
  1603:           return value;
  1604:         }
  1605:       }
  1606:       return "";
  1607:     }  //sgiLoad()
  1608: 
  1609:     //gate.sgiSave ()
  1610:     //  設定ファイルに書き出す
  1611:     @Override public void sgiSave (String text) {
  1612:       JSObject localStorage = XEiJApplet.appGetJSObject (XEiJApplet.appWindow, "localStorage");  //window.localStorage
  1613:       if (localStorage != null) {
  1614:         XEiJApplet.appCallString (localStorage, "setItem", sgaItemName, text);
  1615:       }
  1616:     }  //sgiSave(String)
  1617: 
  1618:     //gate.sgiDelete ()
  1619:     //  設定ファイルを削除する
  1620:     @Override public void sgiDelete () {
  1621:       JSObject localStorage = XEiJApplet.appGetJSObject (XEiJApplet.appWindow, "localStorage");  //window.localStorage
  1622:       if (localStorage != null) {
  1623:         XEiJApplet.appCallString (localStorage, "removeItem", sgaItemName);
  1624:       }
  1625:     }  //sgiDelete()
  1626: 
  1627:   }  //class SGSApplet
  1628: 
  1629: 
  1630: 
  1631:   //================================================================================
  1632:   //$$SGJ JNLPの設定
  1633:   //  JNLPのときパラメータの読み取りと設定の入出力を行う
  1634:   //  *.jnlpファイルの<application-desc><argument>~</argument></application-desc>で指定されたパラメータを読み取る
  1635:   //  PersistenceServiceを用いてローカルファイルに設定を保存する
  1636:   //    Windows7の場合
  1637:   //      C:/Users/ユーザー名/AppData/LocalLow/Sun/Java/Deployment/cache/6.0/muffin/
  1638:   //    に保存される
  1639:   //    保存されたローカルファイルの残骸はJavaコントロールパネルで削除できる
  1640:   //
  1641:   //  ServiceManagerはJNLPでなければクラスパスが通っていないので初期化することもできない
  1642:   //  XEiJのstaticメソッドにstaticメソッドのServiceManager.lookup()を呼び出すコードがあると、
  1643:   //  JNLPでないときXEiJをロードしたときにServiceManagerを初期化しようとしてエラーが出て起動できない
  1644:   //  XEiJをロードしたときにエラーが出るのでServiceManager.lookup()を呼び出さなくてもtry~catchで囲んでも同じ
  1645:   public static class SGSJnlp implements SGSInterface {
  1646: 
  1647:     private static final int SGJ_MAXSIZE = 1024 * 64;  //設定ファイルの最大サイズ。64KB。SRAMの内容が複数入るので大きめにしておく
  1648: 
  1649:     private BasicService sgjBasicService;
  1650:     private PersistenceService sgjPersistenceService;
  1651:     private URL sgjURL;
  1652: 
  1653:     //コンストラクタ
  1654:     private SGSJnlp () {
  1655:       sgjBasicService = null;
  1656:       sgjPersistenceService = null;
  1657:       sgjURL = null;
  1658:       try {
  1659:         sgjBasicService = (BasicService) ServiceManager.lookup ("javax.jnlp.BasicService");
  1660:         sgjPersistenceService = (PersistenceService) ServiceManager.lookup ("javax.jnlp.PersistenceService");
  1661:         if (sgjBasicService != null && sgjPersistenceService != null) {
  1662:           sgjURL = new URL (sgjBasicService.getCodeBase ().toString () + SGS_INI);
  1663:         }
  1664:       } catch (UnavailableServiceException use) {  //利用できない
  1665:       } catch (MalformedURLException mue) {
  1666:       }
  1667:     }  //new SGSJnlp()
  1668: 
  1669:     //map = gate.sgiGetParameters ()
  1670:     //  パラメータを読み取る
  1671:     @Override public HashMap<String,String> sgiGetParameters () {
  1672:       return sgsGetArgumentParameters ();
  1673:     }  //sgiGetParameters()
  1674: 
  1675:     //text = gate.sgiLoad ()
  1676:     //  設定ファイルを読み込む
  1677:     @Override public String sgiLoad () {
  1678:       if (sgjURL != null) {
  1679:         FileContents fc;
  1680:         try {
  1681:           fc = sgjPersistenceService.get (sgjURL);
  1682:         } catch (FileNotFoundException fnfe) {  //ファイルが存在しない
  1683:           return "";
  1684:         } catch (IOException ioe) {  //入出力エラー
  1685:           return "";
  1686:         }
  1687:         try (BufferedInputStream in = new BufferedInputStream (fc.getInputStream ())) {
  1688:           int l = (int) fc.getLength ();
  1689:           byte[] bb = new byte[l];
  1690:           int k = 0;
  1691:           while (k < l) {
  1692:             int t = in.read (bb, k, l - k);
  1693:             if (t < 0) {
  1694:               break;
  1695:             }
  1696:             k += t;
  1697:           }
  1698:           if (k == l) {  //最後まで読み出せた
  1699:             return new String (bb, "UTF-8");
  1700:           }
  1701:         } catch (IOException ioe) {  //入出力エラー
  1702:           return "";
  1703:         }
  1704:       }  //if sgjURL!=null
  1705:       return "";
  1706:     }  //sgiLoad()
  1707: 
  1708:     //gate.sgiSave ()
  1709:     //  設定ファイルに書き出す
  1710:     @Override public void sgiSave (String text) {
  1711:       if (sgjURL != null) {
  1712:         FileContents fc;
  1713:         try {
  1714:           fc = sgjPersistenceService.get (sgjURL);
  1715:         } catch (FileNotFoundException fnfe) {  //ファイルが存在しない
  1716:           try {
  1717:             sgjPersistenceService.create (sgjURL, SGJ_MAXSIZE);  //ファイルを作る
  1718:             sgjPersistenceService.setTag (sgjURL, PersistenceService.DIRTY);  //サーバがコピーを持っていないのでdirty
  1719:             try {
  1720:               fc = sgjPersistenceService.get (sgjURL);
  1721:             } catch (FileNotFoundException fnfe2) {  //ファイルが存在しない
  1722:               return;
  1723:             }
  1724:           } catch (IOException ioe) {  //入出力エラー
  1725:             return;
  1726:           }
  1727:         } catch (IOException ioe) {  //入出力エラー
  1728:           return;
  1729:         }
  1730:         try (BufferedOutputStream out = new BufferedOutputStream (fc.getOutputStream (true))) {
  1731:           out.write (text.getBytes ("UTF-8"));
  1732:         } catch (IOException ioe) {  //入出力エラー
  1733:           return;
  1734:         }
  1735:       }
  1736:     }  //sgiSave(String)
  1737: 
  1738:     //gate.sgiDelete ()
  1739:     //  設定ファイルを削除する
  1740:     @Override public void sgiDelete () {
  1741:       if (sgjURL != null) {
  1742:         try {
  1743:           sgjPersistenceService.delete (sgjURL);
  1744:         } catch (IOException ioe) {  //入出力エラー
  1745:           return;
  1746:         }
  1747:       }
  1748:     }  //sgiDelete()
  1749: 
  1750:   }  //class SGSJnlp
  1751: 
  1752: 
  1753: 
  1754:   //================================================================================
  1755:   //$$SGL ローカルの設定
  1756:   //  ローカルのときパラメータの読み取りと設定の入出力を行う
  1757:   //  で指定されたパラメータを読み取る
  1758:   //  ホームディレクトリに設定ファイルを作る
  1759:   public static class SGSLocal implements SGSInterface {
  1760: 
  1761:     //map = gate.sgiGetParameters ()
  1762:     //  パラメータを読み取る
  1763:     @Override public HashMap<String,String> sgiGetParameters () {
  1764:       return sgsGetArgumentParameters ();
  1765:     }  //sgiGetParameters()
  1766: 
  1767:     //text = gate.sgiLoad ()
  1768:     //  設定ファイルを読み込む
  1769:     @Override public String sgiLoad () {
  1770:       StringBuilder sb = new StringBuilder ();
  1771:       if (sgsLocalIniFile.isFile ()) {
  1772:         try (BufferedReader r = new BufferedReader (new InputStreamReader (new FileInputStream (sgsLocalIniFile), "UTF-8"))) {
  1773:           for (String line = r.readLine (); line != null; line = r.readLine ()) {
  1774:             sb.append (line).append ('\n');
  1775:           }
  1776:         } catch (IOException ioe) {  //入出力エラー
  1777:           return "";
  1778:         }
  1779:       }
  1780:       return sb.toString ();
  1781:     }  //sgiLoad()
  1782: 
  1783:     //gate.sgiSave ()
  1784:     //  設定ファイルに書き出す
  1785:     @Override public void sgiSave (String text) {
  1786:       //内容が変化していなければ何もしない
  1787:       //  内容が変化していないのに保存すると*.bakの意味がなくなる
  1788:       if (sgiLoad ().equals (text)) {  //内容が変化していない
  1789:         return;
  1790:       }
  1791:       //親ディレクトリがなければ作る
  1792:       File parentFile = sgsLocalIniFile.getParentFile ();
  1793:       if (parentFile != null &&  //ルートディレクトリの可能性があるのでparentFile==nullは素通りさせる
  1794:           !parentFile.isDirectory () && !parentFile.mkdir ()) {  //親ディレクトリがなくて作れない
  1795:         return;
  1796:       }
  1797:       //*.tmpを削除する
  1798:       File tmpFile = new File (sgsLocalIniPath + ".tmp");
  1799:       if (tmpFile.exists () && !tmpFile.delete ()) {  //*.tmpがあるが*.tmpを削除できない
  1800:         return;
  1801:       }
  1802:       //*.tmpに書き出す
  1803:       try (BufferedWriter w = new BufferedWriter (new OutputStreamWriter (new FileOutputStream (tmpFile), "UTF-8"))) {
  1804:         w.write (text);
  1805:       } catch (IOException ioe) {  //入出力エラー
  1806:         return;
  1807:       }
  1808:       //設定ファイルを*.bakにリネームする
  1809:       //  javaのFileのrenameToはPerlと違って上書きしてくれないので明示的に削除またはリネームする必要がある
  1810:       File bakFile = new File (sgsLocalIniPath + ".bak");
  1811:       if (sgsLocalIniFile.exists () &&  //設定ファイルがあるが
  1812:           (bakFile.exists () && !bakFile.delete () ||  //*.bakがあるが*.bakを削除できないまたは
  1813:            !sgsLocalIniFile.renameTo (bakFile))) {  //設定ファイルを*.bakにリネームできない
  1814:         return;
  1815:       }
  1816:       //*.tmpを設定ファイルにリネームする
  1817:       //  javaのFileのrenameToはPerlと違って上書きしてくれないので明示的に削除またはリネームする必要がある
  1818:       if (!tmpFile.renameTo (sgsLocalIniFile)) {  //*.tmpを設定ファイルにリネームできない
  1819:         return;
  1820:       }
  1821:     }  //sgiSave(String)
  1822: 
  1823:     //gate.sgiDelete ()
  1824:     //  設定ファイルを削除する
  1825:     @Override public void sgiDelete () {
  1826:       //設定ファイルを*.bakにリネームする
  1827:       //  javaのFileのrenameToはPerlと違って上書きしてくれないので明示的に削除またはリネームする必要がある
  1828:       File bakFile = new File (sgsLocalIniPath + ".bak");
  1829:       if (sgsLocalIniFile.exists () &&  //設定ファイルがあるが
  1830:           (bakFile.exists () && !bakFile.delete () ||  //*.bakがあるが*.bakを削除できないまたは
  1831:            !sgsLocalIniFile.renameTo (bakFile))) {  //設定ファイルを*.bakにリネームできない
  1832:         return;
  1833:       }
  1834:       //設定ファイルを削除する
  1835:       if (sgsLocalIniFile.exists () && !sgsLocalIniFile.delete ()) {  //設定ファイルがあるが設定ファイルを削除できない
  1836:         return;
  1837:       }
  1838:     }  //sgiDelete()
  1839: 
  1840:   }  //class SGSLocal
  1841: 
  1842: 
  1843: 
  1844: }  //class SGS
  1845: 
  1846: 
  1847: