ByteArray.java
     1: //========================================================================================
     2: //  ByteArray.java
     3: //    en:Byte array manipulation -- It manipulates byte arrays.
     4: //    ja:byte配列操作 -- byte配列を操作します。
     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.io.*;
    16: import java.util.zip.*;
    17: 
    18: public class ByteArray {
    19: 
    20:   //d = byaRbs (bb, a)
    21:   //  リードバイト符号拡張
    22:   //  インライン展開する
    23:   public static byte byaRbs (byte[] bb, int a) {
    24:     return bb[a];
    25:   }  //byaRbs
    26: 
    27:   //d = byaRbz (bb, a)
    28:   //  リードバイトゼロ拡張
    29:   //  インライン展開する
    30:   public static int byaRbz (byte[] bb, int a) {
    31:     return bb[a] & 255;
    32:   }  //byaRbz
    33: 
    34:   //d = byaRws (bb, a)
    35:   //  リードワード符号拡張
    36:   public static int byaRws (byte[] bb, int a) {
    37:     return bb[a] << 8 | bb[a + 1] & 255;
    38:   }  //byaRws
    39: 
    40:   //d = byaRiws (bb, a)
    41:   //  リトルエンディアンリードワード符号拡張
    42:   public static int byaRiws (byte[] bb, int a) {
    43:     return bb[a + 1] << 8 | bb[a] & 255;
    44:   }  //byaRiws
    45: 
    46:   //d = byaRwz (bb, a)
    47:   //  リードワードゼロ拡張
    48:   public static int byaRwz (byte[] bb, int a) {
    49:     return (char) (bb[a] << 8 | bb[a + 1] & 255);
    50:   }  //byaRwz
    51: 
    52:   //d = byaRiwz (bb, a)
    53:   //  リトルエンディアンリードワードゼロ拡張
    54:   public static int byaRiwz (byte[] bb, int a) {
    55:     return (char) (bb[a + 1] << 8 | bb[a] & 255);
    56:   }  //byaRiwz
    57: 
    58:   //d = byaRls (bb, a)
    59:   //  リードロング符号拡張
    60:   public static int byaRls (byte[] bb, int a) {
    61:     return bb[a] << 24 | (bb[a + 1] & 255) << 16 | (char) (bb[a + 2] << 8 | bb[a + 3] & 255);
    62:   }  //byaRls
    63: 
    64:   //d = byaRils (bb, a)
    65:   //  リトルエンディアンリードロング符号拡張
    66:   public static int byaRils (byte[] bb, int a) {
    67:     return bb[a + 3] << 24 | (bb[a + 2] & 255) << 16 | (char) (bb[a + 1] << 8 | bb[a] & 255);
    68:   }  //byaRils
    69: 
    70:   //d = byaRqs (bb, a)
    71:   //  リードクワッド符号拡張
    72:   public static long byaRqs (byte[] bb, int a) {
    73:     return (long) byaRls (bb, a) << 32 | byaRls (bb, a + 4) & 0xffffffffL;
    74:   }  //byaRqs
    75: 
    76:   //sb = byaRstr (sb, bb, a, l)
    77:   //  リードストリング
    78:   //  文字列をSJISから変換しながら読み出す
    79:   //  対応する文字がないときは0xfffdになる
    80:   //  制御コードは'.'になる
    81:   public static StringBuilder byaRstr (StringBuilder sb, byte[] bb, int a, int l) {
    82:     for (int i = 0; i < l; i++) {
    83:       int s = bb[a + i] & 255;
    84:       char c;
    85:       if (0x81 <= s && s <= 0x9f || 0xe0 <= s && s <= 0xef) {  //SJISの2バイトコードの1バイト目
    86:         int t = a + 1 < l ? bb[a + 1] & 255 : 0;
    87:         if (0x40 <= t && t != 0x7f && t <= 0xfc) {  //SJISの2バイトコードの2バイト目
    88:           c = CharacterCode.chrSJISToChar[s << 8 | t];  //2バイトで変換する
    89:           if (c == 0) {  //対応する文字がない
    90:             c = '\ufffd';
    91:           }
    92:           a++;
    93:         } else {  //SJISの2バイトコードの2バイト目ではない
    94:           c = '.';  //SJISの2バイトコードの1バイト目ではなかった
    95:         }
    96:       } else {  //SJISの2バイトコードの1バイト目ではない
    97:         c = CharacterCode.chrSJISToChar[s];  //1バイトで変換する
    98:         if (c == 0) {  //対応する文字がない
    99:           c = '\ufffd';
   100:         }
   101:       }
   102:       sb.append (c);
   103:     }
   104:     return sb;
   105:   }  //byaRstr
   106: 
   107:   //byaWb (bb, a, d)
   108:   //  ライトバイト
   109:   public static void byaWb (byte[] bb, int a, int d) {
   110:     bb[a    ] = (byte)  d;
   111:   }  //byaWb
   112: 
   113:   //byaWw (bb, a, d)
   114:   //  ライトワード
   115:   public static void byaWw (byte[] bb, int a, int d) {
   116:     bb[a    ] = (byte) (d >> 8);
   117:     bb[a + 1] = (byte)  d;
   118:   }  //byaWw
   119: 
   120:   //byaWwArray (bb, a, da)
   121:   //  ライトワードアレイ
   122:   public static void byaWwArray (byte[] bb, int a, int[] da) {
   123:     for (int i = 0, l = da.length; i < l; i++) {
   124:       int d = da[i];
   125:       bb[a    ] = (byte) (d >> 8);
   126:       bb[a + 1] = (byte)  d;
   127:       a += 2;
   128:     }
   129:   }  //byaWwArray
   130: 
   131:   //byaWiw (bb, a, d)
   132:   //  リトルエンディアンライトワード
   133:   public static void byaWiw (byte[] bb, int a, int d) {
   134:     bb[a + 1] = (byte) (d >> 8);
   135:     bb[a    ] = (byte)  d;
   136:   }  //byaWiw
   137: 
   138:   //byaWl (bb, a, d)
   139:   //  ライトロング
   140:   public static void byaWl (byte[] bb, int a, int d) {
   141:     bb[a    ] = (byte) (d >> 24);
   142:     bb[a + 1] = (byte) (d >> 16);
   143:     bb[a + 2] = (byte) (d >>  8);
   144:     bb[a + 3] = (byte)  d;
   145:   }  //byaWl
   146: 
   147:   //byaWil (bb, a, d)
   148:   //  リトルエンディアンライトロング
   149:   public static void byaWil (byte[] bb, int a, int d) {
   150:     bb[a + 3] = (byte) (d >> 24);
   151:     bb[a + 2] = (byte) (d >> 16);
   152:     bb[a + 1] = (byte) (d >>  8);
   153:     bb[a    ] = (byte)  d;
   154:   }  //byaWil
   155: 
   156:   //a = byaWstr (bb, a, s)
   157:   //  ライトストリング
   158:   //  文字列をSJISに変換しながら書き込む
   159:   //  SJISに変換できない文字は'※'になる
   160:   //  文字列の直後のアドレスを返す
   161:   public static int byaWstr (byte[] bb, int a, String s) {
   162:     int l = s.length ();
   163:     for (int i = 0; i < l; i++) {
   164:       int c = CharacterCode.chrCharToSJIS[s.charAt (i)];
   165:       if (c == 0 && s.charAt (i) != '\0') {
   166:         c = 0x81a6;  //'※'
   167:       }
   168:       if (c >> 8 != 0) {
   169:         bb[a++] = (byte) (c >> 8);
   170:       }
   171:       bb[a++] = (byte) c;
   172:     }
   173:     return a;
   174:   }  //byaWstr
   175: 
   176:   //byaCmp (bbx, ax, sx, bby, ay, sy)
   177:   //  bbx[ax..ax+sx-1]-bby[ay..ay+sy-1]
   178:   public static int byaCmp (byte[] bbx, int ax, int sx, byte[] bby, int ay, int sy) {
   179:     int i;
   180:     for (i = 0; i < sx && i < sy; i++) {
   181:       int x = 0xff & bbx[ax + i];
   182:       int y = 0xff & bby[ay + i];
   183:       if (x != y) {
   184:         return x - y;
   185:       }
   186:     }
   187:     return sx - sy;
   188:   }  //byaCmp
   189: 
   190:   //byaDump (bb, st, ed)
   191:   //  バイトバッファをダンプする
   192:   public static void byaDump (byte[] bb, int p, int q) {
   193:     for (int p0 = p & -16, q0 = q + 15 & -16; p0 < q0; p0 += 1024) {
   194:       StringBuilder sb = new StringBuilder ();  //StringBuilderは32MBを超えられないので適当な間隔で作り直す必要がある
   195:       for (int p1 = p0, q1 = Math.min (p0 + 1024, q0); p1 < q1; p1 += 16) {
   196:         XEiJ.fmtHex8 (sb, p1).append (' ');
   197:         for (int p2 = p1, q2 = p1 + 16; p2 < q2; p2++) {
   198:           if (p <= p2 && p2 < q) {
   199:             XEiJ.fmtHex2 (sb.append (' '), bb[p2]);
   200:           } else {
   201:             sb.append (' ').append (' ').append (' ');
   202:           }
   203:         }
   204:         sb.append (' ').append (' ');
   205:         int h = 0;  //繰り越した文字
   206:         for (int p2 = p1, q2 = p1 + 16; p2 < q2 || p2 == q2 && h != 0; p2++) {
   207:           int l = p <= p2 && p2 < q ? bb[p2] & 255 : ' ';  //今回の文字
   208:           if ((0x81 <= h && h <= 0x9f || 0xe0 <= h && h <= 0xef) &&  //繰り越した文字はSJISの1バイト目かつ
   209:               (0x40 <= l && l != 0x7f && l <= 0xfc)) {  //今回の文字はSJISの2バイト目
   210:             l |= h << 8;
   211:             int c = CharacterCode.chrSJISToChar[l];
   212:             if (c != 0) {  //SJISで変換できる
   213:               sb.append ((char) c);
   214:             } else {  //SJISだが変換できない
   215:               sb.append ('※');
   216:             }
   217:             h = 0;
   218:           } else {  //繰り越した文字と今回の文字を合わせてもSJISにならない
   219:             if (h != 0) {  //繰り越した文字を吐き出す
   220:               sb.append ('.');
   221:               h = 0;
   222:             }
   223:             //この時点で繰り越した文字はない
   224:             if (0x81 <= l && l <= 0x9f || 0xe0 <= l && l <= 0xef) {  //繰り越した文字がなく、今回の文字はSJISの1バイト目
   225:               h = l;  //繰り越す
   226:             } else {  //繰り越した文字がなく、今回の文字はSJISの1バイト目ではない
   227:               int c = CharacterCode.chrSJISToChar[l];
   228:               if (0x20 <= c && c != 0x7f) {  //ASCIIまたは半角カナ
   229:                 sb.append ((char) c);
   230:               } else {  //SJISの1バイト目ではなく、ASCIIまたは半角カナでもない
   231:                 sb.append ('.');
   232:               }
   233:             }
   234:           }
   235:         }
   236:         sb.append ('\n');
   237:       }
   238:       System.out.print (sb.toString ());
   239:     }
   240:   }  //byaDump
   241: 
   242: /*
   243:   public static final char[] BYA_BASE64_ENCODE_TABLE = {
   244:     'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P',
   245:     'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f',
   246:     'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v',
   247:     'w', 'x', 'y', 'z', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '+', '/',
   248:   };
   249: */
   250:   public static final char[] BYA_BASE64_ENCODE_TABLE = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/".toCharArray ();
   251: 
   252:   //s = byaEncodeBase64 (bb)
   253:   //s = byaEncodeBase64 (bb, o, l)
   254:   //  base64変換
   255:   //  https://tools.ietf.org/html/rfc4648
   256:   public static String byaEncodeBase64 (byte[] bb) {
   257:     return byaEncodeBase64 (bb, 0, bb.length);
   258:   }  //byaEncodeBase64(byte[])
   259:   public static String byaEncodeBase64 (byte[] bb, int o, int l) {
   260:     char[] w = new char[(l + 2) / 3 << 2];
   261:     l += o - 2;
   262:     int i, j;
   263:     for (i = o, j = 0; i < l; i += 3, j += 4) {
   264:       int c = bb[i] & 255;
   265:       int d = bb[i + 1] & 255;
   266:       int e = bb[i + 2] & 255;
   267:       //cccccccc dddddddd eeeeeeee
   268:       //cccccc ccdddd ddddee eeeeee
   269:       w[j    ] = BYA_BASE64_ENCODE_TABLE[c >> 2];
   270:       w[j + 1] = BYA_BASE64_ENCODE_TABLE[(c & 3) << 4 | d >> 4];
   271:       w[j + 2] = BYA_BASE64_ENCODE_TABLE[(d & 15) << 2 | e >> 6];
   272:       w[j + 3] = BYA_BASE64_ENCODE_TABLE[e & 63];
   273:     }
   274:     l += 2;
   275:     if (i < l) {
   276:       int c = bb[i] & 255;
   277:       int d = i + 1 < l ? bb[i + 1] & 255 : 0;
   278:       int e = i + 2 < l ? bb[i + 2] & 255 : 0;
   279:       w[j    ] = BYA_BASE64_ENCODE_TABLE[c >> 2];
   280:       w[j + 1] = BYA_BASE64_ENCODE_TABLE[(c & 3) << 4 | d >> 4];
   281:       w[j + 2] = i + 1 < l ? BYA_BASE64_ENCODE_TABLE[(d & 15) << 2 | e >> 6] : '=';
   282:       w[j + 3] = i + 2 < l ? BYA_BASE64_ENCODE_TABLE[e & 63] : '=';
   283:     }
   284:     return new String (w);
   285:   }  //byaEncodeBase64
   286: 
   287:   static {
   288:     if (false) {
   289:       System.out.println (byaEncodeBase64 ("".getBytes (XEiJ.ISO_8859_1)));  //""
   290:       System.out.println (byaEncodeBase64 ("f".getBytes (XEiJ.ISO_8859_1)));  //"Zg=="
   291:       System.out.println (byaEncodeBase64 ("fo".getBytes (XEiJ.ISO_8859_1)));  //"Zm8="
   292:       System.out.println (byaEncodeBase64 ("foo".getBytes (XEiJ.ISO_8859_1)));  //"Zm9v"
   293:       System.out.println (byaEncodeBase64 ("foob".getBytes (XEiJ.ISO_8859_1)));  //"Zm9vYg=="
   294:       System.out.println (byaEncodeBase64 ("fooba".getBytes (XEiJ.ISO_8859_1)));  //"Zm9vYmE="
   295:       System.out.println (byaEncodeBase64 ("foobar".getBytes (XEiJ.ISO_8859_1)));  //"Zm9vYmFy"
   296:     }
   297:   }
   298: 
   299: /*
   300:   public static final char[] BYA_BASE64_DECODE_TABLE = {
   301:     //  +1  +2  +3  +4  +5  +6  +7  +8  +9  +a  +b  +c  +d  +e  +f
   302:     64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,  //00
   303:     64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,  //10
   304:     64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 62, 64, 64, 64, 63,  //20
   305:     52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 64, 64, 64, 64, 64, 64,  //30
   306:     64,  0,  1,  2,  3,  4,  5,  6,  7,  8,  9, 10, 11, 12, 13, 14,  //40
   307:     15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 64, 64, 64, 64, 64,  //50
   308:     64, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40,  //60
   309:     41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 64, 64, 64, 64, 64,  //70
   310:   };
   311: */
   312:   public static final char[] BYA_BASE64_DECODE_TABLE = "@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@>@@@?456789:;<=@@@@@@@\0\1\2\3\4\5\6\7\b\t\n\13\f\r\16\17\20\21\22\23\24\25\26\27\30\31@@@@@@\32\33\34\35\36\37 !\"#$%&\'()*+,-./0123@@@@@".toCharArray ();
   313: 
   314:   //bb = byaDecodeBase64 (s)
   315:   //  base64逆変換
   316:   //  https://tools.ietf.org/html/rfc4648
   317:   public static byte[] byaDecodeBase64 (String s) {
   318:     char[] w = s.toCharArray ();
   319:     int ll = s.length ();
   320:     int l = 0;
   321:     for (int i = 0; i < ll; i++) {
   322:       char c = w[i];
   323:       if (c <= 127 && (c = BYA_BASE64_DECODE_TABLE[c]) <= 63) {
   324:         w[l++] = c;
   325:       }
   326:     }
   327:     int l3 = l & 3;
   328:     l -= l3;
   329:     byte[] bb = new byte[(l >> 2) * 3 + (l3 <= 1 ? 0 : l3 - 1)];
   330:     int i, j;
   331:     for (i = 0, j = 0; i < l; i += 4, j += 3) {
   332:       char c = w[i];
   333:       char d = w[i + 1];
   334:       char e = w[i + 2];
   335:       char f = w[i + 3];
   336:       //cccccc dddddd eeeeee ffffff
   337:       //ccccccdd ddddeeee eeffffff
   338:       bb[j] = (byte) (c << 2 | d >> 4);
   339:       bb[j + 1] = (byte) (d << 4 | e >> 2);
   340:       bb[j + 2] = (byte) (e << 6 | f);
   341:     }
   342:     if (l3 >= 2) {
   343:       char c = w[i];
   344:       char d = w[i + 1];
   345:       bb[j] = (byte) (c << 2 | d >> 4);
   346:       if (l3 >= 3) {
   347:         char e = w[i + 2];
   348:         bb[j + 1] = (byte) (d << 4 | e >> 2);
   349:       }
   350:     }
   351:     return bb;
   352:   }  //byaDecodeBase64
   353: 
   354:   static {
   355:     if (false) {
   356:       try {
   357:         System.out.println (new String (byaDecodeBase64 (""), "ISO_8859_1"));  //""
   358:         System.out.println (new String (byaDecodeBase64 ("Zg=="), "ISO_8859_1"));  //"f"
   359:         System.out.println (new String (byaDecodeBase64 ("Zm8="), "ISO_8859_1"));  //"fo"
   360:         System.out.println (new String (byaDecodeBase64 ("Zm9v"), "ISO_8859_1"));  //"foo"
   361:         System.out.println (new String (byaDecodeBase64 ("Zm9vYg=="), "ISO_8859_1"));  //"foob"
   362:         System.out.println (new String (byaDecodeBase64 ("Zm9vYmE="), "ISO_8859_1"));  //"fooba"
   363:         System.out.println (new String (byaDecodeBase64 ("Zm9vYmFy"), "ISO_8859_1"));  //"foobar"
   364:       } catch (UnsupportedEncodingException uee) {
   365:       }
   366:     }
   367:   }
   368: 
   369:   //bb = byaEncodeGzip (bb)
   370:   //bb = byaEncodeGzip (bb, o, l)
   371:   //  gzip圧縮
   372:   public static byte[] byaEncodeGzip (byte[] bb) {
   373:     return byaEncodeGzip (bb, 0, bb.length);
   374:   }  //byaEncodeGzip(byte[])
   375:   public static byte[] byaEncodeGzip (byte[] bb, int o, int l) {
   376:     ByteArrayOutputStream baos = new ByteArrayOutputStream ();
   377:     try (GZIPOutputStream gos = new GZIPOutputStream (baos) {
   378:       {
   379:         //def.setLevel (Deflater.BEST_COMPRESSION);  //991467
   380:         def.setLevel (Deflater.DEFAULT_COMPRESSION);  //995563
   381:         //def.setLevel (Deflater.BEST_SPEED);  //1119763
   382:       }
   383:     }) {
   384:       gos.write (bb, o, l);
   385:       gos.flush ();
   386:     } catch (IOException ioe) {
   387:     }
   388:     return baos.toByteArray ();
   389:   }  //byaEncodeGzip
   390: 
   391:   //bb = byaDecodeGzip (bb)
   392:   //bb = byaDecodeGzip (bb, o, l)
   393:   //  gzip解凍
   394:   public static byte[] byaDecodeGzip (byte[] bb) {
   395:     return byaDecodeGzip (bb, 0, bb.length);
   396:   }  //byaDecodeGzip(byte[])
   397:   public static byte[] byaDecodeGzip (byte[] bb, int o, int l) {
   398:     ByteArrayOutputStream baos = new ByteArrayOutputStream ();
   399:     try (GZIPInputStream gis = new GZIPInputStream (new ByteArrayInputStream (bb, o, l))) {
   400:       int tl = 4096;
   401:       byte[] tbb = new byte[tl];
   402:       for (int k = gis.read (tbb, 0, tl); k >= 0; k = gis.read (tbb, 0, tl)) {
   403:         baos.write (tbb, 0, k);
   404:       }
   405:     } catch (IOException ioe) {
   406:     }
   407:     return baos.toByteArray ();
   408:   }  //byaDecodeGzip
   409: 
   410:   public static int crc32 (byte[] b) {
   411:     return crc32 (b, 0, b.length);
   412:   }
   413:   public static int crc32 (byte[] b, int off, int len) {
   414:     CRC32 crc32 = new CRC32 ();
   415:     crc32.reset ();
   416:     crc32.update (b, off, len);
   417:     return (int) crc32.getValue ();
   418:   }
   419: 
   420: }  //class ByteArray
   421: 
   422: 
   423: