HumanMedia.java
     1: //========================================================================================
     2: //  HumanMedia.java
     3: //    en:Human68k media -- It initializes a Human68k file system.
     4: //    ja:Human68kメディア -- Human68kのファイルシステムを初期化します。
     5: //  Copyright (C) 2003-2023 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: //  https://stdkmd.net/xeij/
    11: //========================================================================================
    12: 
    13: package xeij;
    14: 
    15: import java.lang.*;  //Boolean,Character,Class,Comparable,Double,Exception,Float,IllegalArgumentException,Integer,Long,Math,Number,Object,Runnable,SecurityException,String,StringBuilder,System
    16: import java.util.*;  //ArrayList,Arrays,Calendar,GregorianCalendar,HashMap,Map,Map.Entry,Timer,TimerTask,TreeMap
    17: 
    18: public class HumanMedia {
    19: 
    20:   //ディレクトリのエントリの属性
    21:   protected static final int HUM_EXECUTABLE = 0b10000000;  //実行可能
    22:   protected static final int HUM_LINK       = 0b01000000;  //シンボリックリンク
    23:   protected static final int HUM_ARCHIVE    = 0b00100000;  //ファイル
    24:   protected static final int HUM_DIRECTORY  = 0b00010000;  //ディレクトリ
    25:   protected static final int HUM_VOLUME     = 0b00001000;  //ボリューム名
    26:   protected static final int HUM_SYSTEM     = 0b00000100;  //システム
    27:   protected static final int HUM_HIDDEN     = 0b00000010;  //不可視
    28:   protected static final int HUM_READONLY   = 0b00000001;  //書き込み不可
    29: 
    30:   public int humBytesShiftSector;     //        1セクタあたりのバイト数のシフトカウント
    31:   public int humBytesPerSector;       //0000.w  1セクタあたりのバイト数(2の累乗)
    32:   public int humSectorsShiftCluster;  //        1クラスタあたりのセクタ数のシフトカウント
    33:   public int humSectorsPerCluster;    //0002.b  1クラスタあたりのセクタ数(2の累乗)
    34:   public int humBytesShiftCluster;    //        1クラスタあたりのバイト数のシフトカウント
    35:   public int humBytesPerCluster;      //        1クラスタあたりのバイト数(2の累乗)
    36:   public int humFatCount;             //0003.b  FAT領域の個数
    37:   public int humReservedSectors;      //0004.w  予約領域のセクタ数(FAT領域の先頭セクタ番号)
    38:   public int humRootEntries;          //0006.w  ルートディレクトリに入るエントリ数
    39:   public int humEntriesPerSector;     //        1セクタあたりのエントリ数
    40:   public int humRootSectors;          //        ルートディレクトリのセクタ数
    41:   public int humMediaByte;            //        メディアバイト
    42:   public int humFatID;                //000a.b  FATID
    43:   public boolean humFat12;            //        FATの種類(true=FAT12,false=FAT16)
    44:   public int humFatMarker;            //        FATマーカー(FATID<<24|(humFat12?0x00ffff00|0x00ffffff))
    45:   public int humFatTailCode;          //        FATの終端コード(humFat12?0xfff:0xffff)
    46:   public int humFatSectors;           //000b.b  1個のFAT領域に使用するセクタ数
    47:   public int humPartitionSectors;     //000c.l  パーティションのセクタ数
    48:   public int humFatAndDataSectors;    //        FAT領域とデータ領域を合わせたセクタ数。ルートディレクトリを跨いでいるので連続しているわけではない
    49:   public int humDataClustersPlus2;    //        データ領域のクラスタ数+2
    50:   public long humPartitionStartByte;  //        ディスクの先頭からパーティションの先頭までのバイト数
    51:   public long humFatStartByte;        //        ディスクの先頭からFAT領域の先頭までのバイト数
    52:   public int humRootStartSector;      //        ルートディレクトリの先頭セクタ番号
    53:   public long humRootStartByte;       //        ディスクの先頭からルートディレクトリの先頭までのバイト数
    54:   public int humDataStartSector;      //        データ領域の先頭セクタ番号
    55:   public long humDataStartByte;       //        ディスクの先頭からデータ領域の先頭までのバイト数
    56:   public long humDataEndByte;         //        ディスクの先頭からデータ領域の末尾までのバイト数
    57:   public long humPartitionEndByte;    //        ディスクの先頭からパーティションの末尾までのバイト数
    58:   public long humDiskEndByte;         //        ディスクのバイト数
    59: 
    60:   public HumanMedia (int bytesPerSector, int sectorsPerCluster, int fatCount,
    61:                      int reservedSectors, int rootEntries, int mediaByte, int fatID, int fatSectors,
    62:                      long diskEndByte) {
    63:     this (bytesPerSector, sectorsPerCluster, fatCount,
    64:           reservedSectors, rootEntries, mediaByte, fatID, fatSectors,
    65:           diskEndByte, 0L, diskEndByte);
    66:   }  //new HumanMedia(int,int,int,int,int,int,int,long)
    67:   public HumanMedia (int bytesPerSector, int sectorsPerCluster, int fatCount,
    68:                      int reservedSectors, int rootEntries, int mediaByte, int fatID, int fatSectors,
    69:                      long diskEndByte, long partitionStartByte) {
    70:     this (bytesPerSector, sectorsPerCluster, fatCount,
    71:           reservedSectors, rootEntries, mediaByte, fatID, fatSectors,
    72:           diskEndByte, partitionStartByte, diskEndByte);
    73:   }  //new HumanMedia(int,int,int,int,int,int,int,long,long)
    74:   public HumanMedia (int bytesPerSector, int sectorsPerCluster, int fatCount,
    75:                      int reservedSectors, int rootEntries, int mediaByte, int fatID, int fatSectors,
    76:                      long diskEndByte, long partitionStartByte, long partitionEndByte) {
    77:     //定数で与えるもの
    78:     humBytesPerSector = bytesPerSector;  //1セクタあたりのバイト数(2の累乗)
    79:     humFatCount = fatCount;  //FAT領域の個数
    80:     humReservedSectors = reservedSectors;  //予約領域のセクタ数(FAT領域の先頭セクタ番号)
    81:     humRootEntries = rootEntries;  //ルートディレクトリに入るエントリ数
    82:     humMediaByte = mediaByte;  //メディアバイト
    83:     humFatID = fatID;  //FATID
    84:     humPartitionStartByte = partitionStartByte;  //ディスクの先頭からパーティションの先頭までのバイト数
    85:     humPartitionEndByte = partitionEndByte;  //ディスクの先頭からパーティションの末尾までのバイト数
    86:     humDiskEndByte = diskEndByte;  //ディスクのバイト数
    87:     //定数から求まるもの
    88:     humBytesShiftSector = Integer.numberOfTrailingZeros (humBytesPerSector);  //1セクタあたりのバイト数のシフトカウント
    89:     humPartitionSectors = (int) (humPartitionEndByte - humPartitionStartByte >> humBytesShiftSector);  //パーティションのセクタ数
    90:     humFatStartByte = humPartitionStartByte + (long) (humReservedSectors << humBytesShiftSector);  //ディスクの先頭からFAT領域の先頭までのバイト数
    91:     humEntriesPerSector = humBytesPerSector >> 5;  //1セクタあたりのエントリ数
    92:     humRootSectors = humBytesToSectors (humRootEntries << 5);  //ルートディレクトリのセクタ数。端数を切り上げる
    93:     //1クラスタあたりのセクタ数を決める
    94:     //  データ領域のクラスタ数の上限を65520(0xfff0)として1クラスタあたりのセクタ数がなるべく小さくなるようにする
    95:     //    1クラスタあたりのセクタ数は必ずしも小さければよいとは限らないが、ここではなるべく小さくなるようにする
    96:     //  FAT16で65520クラスタでFAT領域の末尾に隙間を空けなかった場合のセクタ数がFAT領域とデータ領域を合わせたセクタ数に満たないとき1クラスタあたりのセクタ数を大きくする
    97:     //    65520クラスタのときFAT領域は128KBなのでFAT領域とデータ領域を合わせて128+65520=65648KBまでは1クラスタ=1セクタでよい
    98:     //    65649KB以上のときもFAT領域の末尾に隙間を空ければ1クラスタ=1セクタにすることは可能だが、そのような割り当て方はしないことにする
    99:     //  メモ
   100:     //    FORMAT.Xは全領域のセクタ数を65520以下になるまで右にシフトしている
   101:     //    FORMAT.X  00005024
   102:     humFatAndDataSectors = humPartitionSectors - humReservedSectors - humRootSectors;  //FAT領域とデータ領域を合わせたセクタ数。ルートディレクトリを跨いでいるので連続しているわけではない
   103:     if (sectorsPerCluster >= 0) {  //1クラスタあたりのセクタ数が指定されている
   104:       humSectorsShiftCluster = Integer.numberOfTrailingZeros (sectorsPerCluster);  //1クラスタあたりのセクタ数のシフトカウント
   105:       humSectorsPerCluster = sectorsPerCluster;  //1クラスタあたりのセクタ数(2の累乗)
   106:     } else {  //1クラスタあたりのセクタ数が指定されていない
   107:       humSectorsShiftCluster = 0;  //1クラスタあたりのセクタ数のシフトカウント
   108:       humSectorsPerCluster = 1;  //1クラスタあたりのセクタ数(2の累乗)
   109:       while (humBytesToSectors (2 * (65520 + 2)) * humFatCount + (65520 << humSectorsShiftCluster) < humFatAndDataSectors) {  //FAT16で65520クラスタでFAT領域の末尾に隙間を空けなかった場合のセクタ数がFAT領域とデータ領域を合わせたセクタ数に満たないとき
   110:         humSectorsShiftCluster++;  //1クラスタあたりのセクタ数を2倍にする
   111:       }
   112:       humSectorsPerCluster = 1 << humSectorsShiftCluster;  //1クラスタあたりのセクタ数
   113:     }
   114:     humBytesShiftCluster = humBytesShiftSector + humSectorsShiftCluster;  //1クラスタあたりのバイト数のシフトカウント
   115:     humBytesPerCluster = 1 << humBytesShiftCluster;  //1クラスタあたりのバイト数(2の累乗)
   116:     //FATの種類を決める
   117:     //  FAT12とFAT16を見分ける唯一の方法はデータ領域のクラスタ数が4085(0xff5)未満か以上かを確認することである
   118:     //    human302  0000ede4  指定されたクラスタ番号のFATを得る
   119:     //    FAT12とFAT16はFATマーカーの長さが異なるが、FAT領域の4バイト目が0xffかどうかでFAT12とFAT16を見分けることはできない
   120:     //    FAT12でも先頭のクラスタが使用中(終端)ならばFAT領域の4バイト目は0xffである
   121:     //  FAT領域とデータ領域を合わせたセクタ数がFAT16で4085クラスタのときのセクタ数に満たなければFAT12、それ以外はFAT16とする
   122:     humFat12 = humFatAndDataSectors < humBytesToSectors (2 * (4085 + 2)) * humFatCount + (4085 << humSectorsShiftCluster);  //FATの種類(true=FAT12,false=FAT16)
   123:     humFatMarker = humFatID << 24 | (humFat12 ? 0x00ffff00 : 0x00ffffff);  //FATマーカー
   124:     humFatTailCode = humFat12 ? 0xfff : 0xffff;  //FATの終端コード
   125:     //1個のFAT領域に使用するセクタ数とデータ領域のクラスタ数を決める
   126:     //  FAT12のときはデータ領域のクラスタ数が4085未満になるように1個のFAT領域に使用するセクタ数を調整する
   127:     //  このときFAT領域を必要最小限に切り詰めてはならない場合があることに注意する
   128:     //  例:4096KBのメモリブロックに予約領域のセクタ数=0、FATの個数=1、ルートディレクトリのエントリ数=128のRAMディスクを作る場合
   129:     //    ルートディレクトリのセクタ数は128/32=4
   130:     //    FAT領域とデータ領域を合わせたセクタ数は4096-0-4=4092
   131:     //    FAT領域とデータ領域を合わせたセクタ数が4085以上なのでFAT16と仮定する
   132:     //    1個のFAT領域に使用するセクタ数はceil(4092*2/1024)=8
   133:     //    データ領域のクラスタ数は4096-0-8*1-4=4084
   134:     //    データ領域のクラスタ数が4085未満なので、FAT16と仮定したにも関わらず実際にはFAT12でアクセスされることになる
   135:     //    FAT12の場合に使用されるFAT領域のセクタ数はceil(ceil(4084*1.5)/1024)=6
   136:     //    ここでFAT領域のセクタ数を8から6に切り詰めると、データ領域のクラスタ数は4096-0-6*1-4=4086
   137:     //    今度はデータ領域のクラスタ数が4085以上なので、FAT領域がFAT12の分しかないのにFAT16でアクセスされることになる
   138:     //    それではFAT領域とルートディレクトリが重なって破壊されてしまう
   139:     //    この場合はFAT12を選択してFAT領域を切り詰めずに2セクタ余らせた状態にしておかなければならない
   140:     if (fatSectors >= 0) {  //1個のFAT領域に使用するセクタ数が指定されている
   141:       humFatSectors = fatSectors;  //1個のFAT領域に使用するセクタ数
   142:       humDataClustersPlus2 = humFatAndDataSectors - humFatSectors * humFatCount >> humSectorsShiftCluster;  //データ領域のクラスタ数+2
   143:     } else {
   144:       humDataClustersPlus2 = (humFatAndDataSectors >> humSectorsShiftCluster) + 2;  //データ領域のクラスタ数+2の最大値
   145:       humDataClustersPlus2 = (
   146:         humFat12 ?
   147:         Math.min (4084,
   148:                   (humFatAndDataSectors - humBytesToSectors (3 * humDataClustersPlus2 + 1 >>> 1) * humFatCount) >> humSectorsShiftCluster) :
   149:         (humFatAndDataSectors - humBytesToSectors (2 * humDataClustersPlus2) * humFatCount) >> humSectorsShiftCluster
   150:         ) + 2;  //データ領域のクラスタ数+2
   151:       humFatSectors = (humFatAndDataSectors - (humDataClustersPlus2 - 2 << humSectorsShiftCluster)) / humFatCount;  //1個のFAT領域に使用するセクタ数
   152:     }
   153:     //ルートディレクトリ
   154:     humRootStartSector = humReservedSectors + humFatSectors * humFatCount;  //ルートディレクトリの先頭セクタ番号
   155:     //humRootStartByte = humFatStartByte + (long) (humFatSectors * humFatCount << humBytesShiftSector);  //ディスクの先頭からルートディレクトリの先頭までのバイト数
   156:     humRootStartByte = humPartitionStartByte + (long) (humRootStartSector << humBytesShiftSector);  //ディスクの先頭からルートディレクトリの先頭までのバイト数
   157:     //データ領域
   158:     humDataStartSector = humRootStartSector + humRootSectors;  //データ領域の先頭セクタ番号
   159:     //humDataStartByte = humRootStartByte + (long) (humRootSectors << humBytesShiftSector);  //ディスクの先頭からデータ領域の先頭までのバイト数
   160:     humDataStartByte = humPartitionStartByte + (long) (humDataStartSector << humBytesShiftSector);  //ディスクの先頭からデータ領域の先頭までのバイト数
   161:     humDataEndByte = humDataStartByte + ((long) (humDataClustersPlus2 - 2) << humBytesShiftCluster);  //ディスクの先頭からデータ領域の末尾までのバイト数
   162:   }  //new HumanMedia(int,int,int,int,int,int,int,long,long,long)
   163: 
   164:   //humPrintInfo ()
   165:   public final void humPrintInfo () {
   166:     System.out.printf ("   humBytesShiftSector=  %12d\n", humBytesShiftSector);
   167:     System.out.printf ("     humBytesPerSector=  %12d\n", humBytesPerSector);
   168:     System.out.printf ("humSectorsShiftCluster=  %12d\n", humSectorsShiftCluster);
   169:     System.out.printf ("  humSectorsPerCluster=  %12d\n", humSectorsPerCluster);
   170:     System.out.printf ("  humBytesShiftCluster=  %12d\n", humBytesShiftCluster);
   171:     System.out.printf ("    humBytesPerCluster=  %12d\n", humBytesPerCluster);
   172:     System.out.printf ("           humFatCount=  %12d\n", humFatCount);
   173:     System.out.printf ("    humReservedSectors=  %12d\n", humReservedSectors);
   174:     System.out.printf ("        humRootEntries=  %12d\n", humRootEntries);
   175:     System.out.printf ("   humEntriesPerSector=  %12d\n", humEntriesPerSector);
   176:     System.out.printf ("        humRootSectors=  %12d\n", humRootSectors);
   177:     System.out.printf ("          humMediaByte=    0x%08x\n", humMediaByte);
   178:     System.out.printf ("              humFatID=    0x%08x\n", humFatID);
   179:     System.out.printf ("              humFat12=  %12b\n", humFat12);
   180:     System.out.printf ("          humFatMarker=    0x%08x\n", humFatMarker);
   181:     System.out.printf ("        humFatTailCode=    0x%08x\n", humFatTailCode);
   182:     System.out.printf ("         humFatSectors=  %12d\n", humFatSectors);
   183:     System.out.printf ("   humPartitionSectors=  %12d\n", humPartitionSectors);
   184:     System.out.printf ("  humFatAndDataSectors=  %12d\n", humFatAndDataSectors);
   185:     System.out.printf ("  humDataClustersPlus2=  %12d\n", humDataClustersPlus2);
   186:     System.out.printf (" humPartitionStartByte=0x%012x\n", humPartitionStartByte);
   187:     System.out.printf ("       humFatStartByte=0x%012x\n", humFatStartByte);
   188:     System.out.printf ("    humRootStartSector=  %12d\n", humRootStartSector);
   189:     System.out.printf ("      humRootStartByte=0x%012x\n", humRootStartByte);
   190:     System.out.printf ("    humDataStartSector=  %12d\n", humDataStartSector);
   191:     System.out.printf ("      humDataStartByte=0x%012x\n", humDataStartByte);
   192:     System.out.printf ("        humDataEndByte=0x%012x\n", humDataEndByte);
   193:     System.out.printf ("   humPartitionEndByte=0x%012x\n", humPartitionEndByte);
   194:     System.out.printf ("        humDiskEndByte=0x%012x\n", humDiskEndByte);
   195:   }  //humPrintInfo()
   196: 
   197:   //sectors = media.humBytesToSectors (bytes)
   198:   //  バイト数からセクタ数を求める
   199:   public final int humBytesToSectors (int bytes) {
   200:     return (bytes + (humBytesPerSector - 1) >> humBytesShiftSector);
   201:   }  //media.humBytesToSectors(int)
   202:   public final int humBytesToSectors (long bytes) {
   203:     return (int) (bytes + (humBytesPerSector - 1) >> humBytesShiftSector);
   204:   }  //media.humBytesToSectors(long)
   205: 
   206:   //media.humWriteFatMarker(bb)
   207:   //  FAT領域の先頭にFATマーカーを書き込む
   208:   //  FAT領域をゼロクリアしてから呼び出すこと
   209:   public void humWriteFatMarker (byte[] bb) {
   210:     //2HDEと2HSのIPLがFAT領域の未使用部分を使っている。IPLが破壊されてしまうのでここでFAT領域をゼロクリアしてはならない
   211:     //Arrays.fill (bb, (int) humFatStartByte, (int) humRootStartByte, (byte) 0);
   212:     for (int i = 0; i < humFatCount; i++) {
   213:       ByteArray.byaWl (bb, (int) humFatStartByte + (humFatSectors * i << humBytesShiftSector), humFatMarker);
   214:     }
   215:   }  //media.humWriteFatMarker(byte[])
   216: 
   217:   //success = media.humCopyHumanSys (bb)
   218:   //  ルートディレクトリにHUMAN.SYSをコピーする
   219:   //  最初に見つけた空きクラスタから連続して書き込むだけなのでフォーマットの直後以外は使用できない
   220:   public boolean humCopyHumanSys (byte[] bb) {
   221:     //HUMAN.SYS
   222:     //      a--s--  12:00:00  1993-09-15  58496  HUMAN.SYS
   223:     byte[] rr = XEiJ.rscGetResource ("HUMAN.SYS");
   224:     if (rr == null || rr.length != 58496) {
   225:       return false;
   226:     }
   227:     humCopySystemFile (bb, "HUMAN   SYS", HUM_ARCHIVE | HUM_SYSTEM, 12 << 11 | 0 << 5 | 0 >> 1, 1993 - 1980 << 9 | 9 << 5 | 15, rr);
   228:     return true;
   229:   }  //media.humCopyHumanSys(byte[])
   230: 
   231:   //success = media.humCopyCommandX (bb)
   232:   //  ルートディレクトリにCOMMAND.Xをコピーする
   233:   //  最初に見つけた空きクラスタから連続して書き込むだけなのでフォーマットの直後以外は使用できない
   234:   public boolean humCopyCommandX (byte[] bb) {
   235:     //COMMAND.X
   236:     //      a-----  12:00:00  1993-02-25  28382  COMMAND.X
   237:     byte[] rr = XEiJ.rscGetResource ("COMMAND.X");
   238:     if (rr == null || rr.length != 28382) {
   239:       return false;
   240:     }
   241:     humCopySystemFile (bb, "COMMAND X  ", HUM_ARCHIVE, 12 << 11 | 0 << 5 | 0 >> 1, 1993 - 1980 << 9 | 2 << 5 | 25, rr);
   242:     return true;
   243:   }  //media.humCopyCommandX(byte[])
   244: 
   245:   //media.humCopySystemFile (bb, name, attr, time, date, rr)
   246:   //  ルートディレクトリにファイルをコピーする
   247:   //  最初に見つけた空きクラスタから連続してコピーするだけなのでフォーマットの直後以外は使用できない
   248:   public void humCopySystemFile (byte[] bb, String name1ext, int attr, int time, int date, byte[] rr) {
   249:     int entry;
   250:     for (entry = (int) humRootStartByte; bb[entry] != 0x00; entry += 32) {  //空きエントリを探す
   251:     }
   252:     ByteArray.byaWstr (bb, entry, name1ext);  //ファイル名1と拡張子
   253:     ByteArray.byaWb (bb, entry + 11, attr);  //属性
   254:     ByteArray.byaWstr (bb, entry + 12, "\0\0\0\0\0\0\0\0\0\0");  //ファイル名2
   255:     ByteArray.byaWiw (bb, entry + 22, time);  //時刻=時<<11|分<<5|秒/2
   256:     ByteArray.byaWiw (bb, entry + 24, date);  //日付=(西暦年-1980)<<9|月<<5|月通日
   257:     int start = 0;  //先頭クラスタ番号
   258:     int size = rr == null ? 0 : rr.length;  //サイズ
   259:     if (size > 0) {
   260:       for (start = 2; humGetFat (bb, start) != 0; start++) {  //空きクラスタを探す
   261:       }
   262:       int end = start + (size - 1 >> humBytesShiftCluster);  //最終クラスタ番号
   263:       for (int cluster = start; cluster < end; cluster++) {
   264:         humSetFat (bb, cluster, cluster + 1);  //使用中
   265:       }
   266:       humSetFat (bb, end, humFatTailCode);  //末尾
   267:       System.arraycopy (rr, 0, bb, (int) humDataStartByte + (start - 2 << humBytesShiftCluster), size);  //本体をコピーする
   268:     }
   269:     ByteArray.byaWiw (bb, entry + 26, start);  //先頭クラスタ番号
   270:     ByteArray.byaWil (bb, entry + 28, size);  //サイズ
   271:   }  //media.humCopySystemFile(byte[],String,int,String,int,int,byte[])
   272: 
   273:   //success = media.humUndel (bb, entry, letter)
   274:   //  削除エントリを復元する
   275:   public boolean humUndel (byte[] bb, int entry, int letter) {
   276:     if ((bb[entry] & 255) != 0xe5) {  //削除エントリではない
   277:       return false;
   278:     }
   279:     int size = ByteArray.byaRils (bb, entry + 28);  //ファイルサイズ
   280:     if (size > 0) {  //ファイルサイズが0ではないので実体が存在する
   281:       int start = ByteArray.byaRiwz (bb, entry + 26);  //先頭クラスタ番号
   282:       int end = start + (size - 1 >> humBytesShiftCluster);  //最終クラスタ番号
   283:       if (humDataClustersPlus2 <= end) {  //クラスタが連続していると仮定するとディスクの末尾からはみ出す
   284:         return false;
   285:       }
   286:       //クラスタが未使用になっていることを確認する
   287:       for (int cluster = start; cluster <= end; cluster++) {
   288:         if (humGetFat (bb, cluster) != 0) {  //クラスタが未使用になっていない
   289:           return false;
   290:         }
   291:       }
   292:       //FATを再構築する
   293:       for (int cluster = start; cluster < end; cluster++) {
   294:         humSetFat (bb, cluster, cluster + 1);
   295:       }
   296:       humSetFat (bb, end, humFatTailCode);
   297:     }
   298:     //エントリを復活させる
   299:     bb[entry] = (byte) letter;
   300:     return true;
   301:   }  //media.humUndel(byte[],int,int)
   302: 
   303:   //media.humDumpFat (bb)
   304:   //  FAT領域をダンプする
   305:   //            +0    +1    +2    +3    +4    +5    +6    +7    +8    +9   +10   +11   +12   +13   +14   +15   +16   +17   +18   +19
   306:   //  #####| ##### ##### ##### ##### ##### ##### ##### ##### ##### ##### ##### ##### ##### ##### ##### ##### ##### ##### ##### #####
   307:   public void humDumpFat (byte[] bb) {
   308:     final int cols = 20;
   309:     StringBuilder sb = new StringBuilder ();
   310:     sb.append ("       ");
   311:     for (int i = 0; i < cols; i++) {
   312:       sb.append (String.format (" %+5d", i));
   313:     }
   314:     sb.append ('\n');
   315:     for (int cluster0 = 0, cluster1 = cols; cluster0 < humDataClustersPlus2; cluster0 = cluster1, cluster1 += cols) {
   316:       sb.append (String.format ("%5d|", cluster0));
   317:       for (int cluster = cluster0; cluster < cluster1; cluster++) {
   318:         if (cluster < 2 || humDataClustersPlus2 <= cluster) {  //範囲外
   319:           sb.append ("      ");
   320:         } else {
   321:           int next = humGetFat (bb, cluster);
   322:           sb.append (next == 0 ? "   ---" :  //空き
   323:                      next != humFatTailCode ? String.format (" %5d", next) :  //先頭または途中
   324:                      "   END");  //終端
   325:         }
   326:       }
   327:       sb.append ('\n');
   328:     }
   329:     System.out.println (sb.toString ());
   330:   }  //media.humDumpFat(byte[])
   331: 
   332:   //next = media.humGetFat (bb, cluster)
   333:   //  FATを読む
   334:   public int humGetFat (byte[] bb, int cluster) {
   335:     if (humFat12) {  //FAT12
   336:       int i = (int) humFatStartByte + 3 * (cluster >> 1);
   337:       return ((cluster & 1) == 0 ?
   338:               bb[i + 1] << 8 & 0xf00 | bb[i    ]      & 0x0ff :  //偶数クラスタ(ML.H..→HML)
   339:               bb[i + 2] << 4 & 0xff0 | bb[i + 1] >> 4 & 0x00f);  //奇数クラスタ(..l.hm→hml)
   340:     } else {  //FAT16
   341:       int i = (int) humFatStartByte + (cluster << 1);
   342:       return (char) (bb[i    ] << 8 | bb[i + 1] & 255);
   343:     }
   344:   }  //media.humGetFat(byte[],int)
   345: 
   346:   //media.humSetFat (bb, cluster, next)
   347:   //  FATに書く
   348:   public void humSetFat (byte[] bb, int cluster, int next) {
   349:     if (humFat12) {  //FAT12
   350:       int i = (int) humFatStartByte + 3 * (cluster >> 1);
   351:       if ((cluster & 1) == 0) {  //偶数クラスタ(HML→ML.H..)
   352:         bb[i    ] = (byte) next;  //ML。next&0x0ff
   353:         bb[i + 1] = (byte) (bb[i + 1] & 0xf0 | next >> 8 & 15);  //.H。(next&0xf00)>>8
   354:       } else {  //奇数クラスタ(hml→..l.hm)
   355:         bb[i + 1] = (byte) (next << 4 | bb[i + 1] & 15);  //l.。(next&0x00f)<<4
   356:         bb[i + 2] = (byte) (next >> 4);  //hm。(next&0xff0)>>4
   357:       }
   358:     } else {  //FAT16
   359:       int i = (int) humFatStartByte + (cluster << 1);
   360:       bb[i    ] = (byte) (next >> 8);
   361:       bb[i + 1] = (byte) next;
   362:     }
   363:   }  //media.humSetFat(byte[],int,int)
   364: 
   365: }  //class HumanMedia
   366: 
   367: 
   368: