JavaでBase64エンコードのデコードプログラムのエラーが出ます。

このQ&Aのポイント
  • JavaでBase64にエンコードしたものをデコードするプログラムでエラーが出ています。コンパイルは通ったのですが、実行したらArrayIndexOutOfBoundsExceptionが発生しています。
  • エラーメッセージによると、問題の行は51行目と23行目ですが、原因がよく分かりません。
  • 質問は初歩的かもしれませんが、どなたか解決方法を教えていただけないでしょうか?
回答を見る
  • ベストアンサー

java

Base64にエンコードしたものをデコードするプログラムです。(汎用性が低いのは仕様です)コンパイルは通ったのですが、実行したら以下のエラーが出てきました。 C:\Users\Owner\Documents\javadev>java Base64Decode2 hello.dat hello2.txt java.lang.ArrayIndexOutOfBoundsException: 97 at Base64Decode2.decode(Base64Decode2.java:51) at Base64Decode2.main(Base64Decode2.java:23) 指定の行を見ても原因がよく分かりません。とても初歩的な質問なのかもしれませんが、お願いします。 以下がプログラムコードです import java.io.*; public class Base64Decode2 { public static void main(String[] args) { // 変換テーブル char[] table = { 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '+', '/'}; InputStream in = null; // 入力データ OutputStream out = null; // 出力先 try { in = new FileInputStream(args[0]); out = new FileOutputStream(args[1]); char[] cs; while ((cs=read4(in)) != null) { int[] buf = decode(cs, table);//ここが問題? for (int i=0; i<buf.length; i++) { System.out.print(buf[i]+", "); } System.out.println(); int[] buf2 = convert6to8(buf); write3(out, buf2); } } catch (Exception e) { e.printStackTrace(); // 例外の情報を表示する } finally { // in, out を閉じる try { in.close(); out.close(); } catch (Exception e) { } } } /** * 8ビットの2進数の列を復号化する. * @param cs * @param table 符号テーブル * @return */ public static int[] decode(char[] cs, char[] table) { int[] buf = new int[cs.length]; for (int i=0; i<buf.length; i++) { buf[i] = table[cs[i]];//ここが問題? } return buf; } public static int[] convert6to8(int[] buf) { String b; int[] buf2; if (buf.length == 2) { b = toBinary(buf[0], 6); buf2 = new int[1]; buf2[0] = fromBinary(b.substring(0, 8)); } else if (buf.length == 3) { b = toBinary(buf[0], 6) + toBinary(buf[1], 6); buf2 = new int[2]; buf2[0] = fromBinary(b.substring(0, 8)); buf2[1] = fromBinary(b.substring(8, 16)); } else { b = toBinary(buf[0], 6) + toBinary(buf[1], 6) + toBinary(buf[2], 6); buf2 = new int[3]; buf2[0] = fromBinary(b.substring(0, 8)); buf2[1] = fromBinary(b.substring(8, 16)); buf2[2] = fromBinary(b.substring(16, 24)); } return buf2; } /** * バイト列 bt の数を順に出力する. * @param bt 数の配列。長さは 3以下. 各数は8ビットの整数 */ public static void write3(OutputStream out, int[] bt) throws IOException { for (int i=0; i<3; i++) { if (i<bt.length) { out.write(bt[i]); } } } /** * in から文字を最大4つ読み出す. * @param in 入力ストリーム * @return 文字の配列。配列長は最大4. 入力終了したときには null を返す. */ public static char[] read4(InputStream in) throws IOException { char[] bs; int n0=in.read(); int n1=in.read(); int n2=in.read(); int n3=in.read(); if (n0 < 0) { // 読み込み終了 bs = null; } else if (n2 < 0 || (char) n2=='=') { bs = new char[2]; bs[0] = (char) n0; bs[1] = (char) n1; } else if (n3 < 0 || (char) n3=='=') { bs = new char[3]; bs[0] = (char) n0; bs[1] = (char) n1; bs[2] = (char) n2; } else { bs = new char[4]; bs[0] = (char) n0; bs[1] = (char) n1; bs[2] = (char) n2; bs[3] = (char) n3; } return bs; } /** * 数を読み取って、nビットの2進数を表す文字列に変換する * @param bt 1バイトの数 * @param n 2進数のビット数 * @return 2進数を表す文字列 */ public static String toBinary(int bt, int n) { String s = Integer.toBinaryString(bt); for (int i=s.length(); i<n; i++) { s = "0" + s; } return s; } /** * 2進数を表す文字列を数に変換する * @param b 2進数を表す文字列 * @return b が表す数 */ public static int fromBinary(String b) { return Integer.parseInt(b, 2); } }

  • Java
  • 回答数2
  • ありがとう数0

質問者が選んだベストアンサー

  • ベストアンサー
  • Tacosan
  • ベストアンサー率23% (3656/15482)
回答No.2

table[0] が 'A' ってことは, エンコードでは「64進表現したときに 0 だったらその桁は A で表しましょう」ってことだよね. ということは, デコードはその逆だから「'A' という文字があったらそれは 0 だと思いましょう」としなきゃならない. なので, 例えば int decoded; for (decoded = 0; decoded < table.length; ++decoded) { if (table[decoded] == cs[i]) { break; } } とすれば cs[i] の内容を 64進に逆変換できる, はず. これを cs 中の全ての要素で行い, しかる後に 6ビット×4桁を 8ビット×3文字に変換すれば戻るんじゃないかな. まあ, 最後にある (かもしれない) '=' についてはそれなりに対応してくれってことで.

その他の回答 (1)

  • Tacosan
  • ベストアンサー率23% (3656/15482)
回答No.1

buf[i] = table[cs[i]]; って, 何を期待しているんだろう. cs[i] の値は調べた?

naginagi0000
質問者

補足

我ながらなぞの処理をしていることに今気づきました。これの対になる下記のエンコードプログラムをまねて書いていたのでわけが分からないことになってます。これでエンコードしたものをデコードするプログラムを作成したいのですが・・・ import java.io.*; public class Base64Encode { public static void main(String[] args) { char[] table = { 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '+', '/'}; InputStream in = null; // 入力データ OutputStream out = null; // 出力先 try { in = new FileInputStream(args[0]); out = new FileOutputStream(args[1]); int[] buf; while ((buf=read(in)) != null) { int[] buf2 = convert8to6(buf); for (int i=0; i<buf.length; i++) { System.out.print(buf[i]+", "); } System.out.println(); char[] cs = encode(buf2, table); write(out, cs); } } catch (Exception e) { e.printStackTrace(); // 例外の情報を表示する } finally { // in, out を閉じる try { in.close(); out.close(); } catch (Exception e) { } } } public static char[] encode(int[] buf2, char[] table) { char[] cs = new char[buf2.length]; for (int i=0; i<cs.length; i++) { cs[i] = table[buf2[i]]; } return cs; } public static int[] convert8to6(int[] buf) { String b; int[] buf2; if (buf.length == 1) { b = toBinary(buf[0], 8) + "0000"; buf2 = new int[2]; buf2[0] = fromBinary(b.substring(0, 6)); buf2[1] = fromBinary(b.substring(6, 12)); } else if (buf.length == 2) { b = toBinary(buf[0], 8) + toBinary(buf[1], 8) + "00"; buf2 = new int[3]; buf2[0] = fromBinary(b.substring(0, 6)); buf2[1] = fromBinary(b.substring(6, 12)); buf2[2] = fromBinary(b.substring(12, 18)); } else { b = toBinary(buf[0], 8) + toBinary(buf[1], 8) + toBinary(buf[2], 8); buf2 = new int[4]; buf2[0] = fromBinary(b.substring(0, 6)); buf2[1] = fromBinary(b.substring(6, 12)); buf2[2] = fromBinary(b.substring(12, 18)); buf2[3] = fromBinary(b.substring(18, 24)); } return buf2; } public static void write(OutputStream out, char[] cs) throws IOException { for (int i=0; i<4; i++) { if (i<cs.length) { out.write(cs[i]); } else { out.write('='); } } } public static int[] read(InputStream in) throws IOException { int[] bs; int n0=in.read(); int n1=in.read(); int n2=in.read(); if (n0 < 0) { // 読み込み終了 bs = null; } else if (n1 < 0) { bs = new int[1]; bs[0] = n0; } else if (n2 < 0) { bs = new int[2]; bs[0] = n0; bs[1] = n1; } else { bs = new int[3]; bs[0] = n0; bs[1] = n1; bs[2] = n2; } return bs; } public static String toBinary(int bt, int n) { String s = Integer.toBinaryString(bt); for (int i=s.length(); i<n; i++) { s = "0" + s; } return s; } public static int fromBinary(String b) { return Integer.parseInt(b, 2); } }

関連するQ&A

  • 多桁 計算プログラム

    下のプログラムを (1)上位桁の不要な0を表示しない (2)3つの数を計算できるようにする (3)0が入力されるまでは入力を受け付けて加算を繰り返す プログラムに改造する方法を教えてください。 #include <stdio.h> #define MAXDIGIT 70 void reset(char*,int); void input(char*,int); void add(char*,char*,char*,int); void add_digit(char ,char ,char ,char* ,char* ); void display(char* ,char* ,char* ,int ); void lineprint(char ,char* ,int ); void linedraw(char ,int ); int main(void) { char a[MAXDIGIT],b[MAXDIGIT],c[MAXDIGIT]; reset(a,MAXDIGIT); reset(b,MAXDIGIT); reset(c,MAXDIGIT); input(a,MAXDIGIT); input(b,MAXDIGIT); add(a,b,c,MAXDIGIT); display(a,b,c,MAXDIGIT); return 0;} void reset(char* buf,int maxdigit) { int i; for(i=0;i<maxdigit;i++) buf[i]=0; return;} void input(char* buf,int maxdigit) { char str[MAXDIGIT]; int i,j; printf("input data:"); scanf("%s",str); i=0; while(str[i]!='\0') i++; j=0; while(i>0){ buf[j]=str[i-1]-'0'; j++; i--; } return;} void add(char* a,char* b,char* c,int maxdigit) { int i; char carry_in,carry_out; i=0; carry_in=0; while(i<maxdigit) { add_digit(a[i],b[i],carry_in,&c[i],&carry_out); carry_in=carry_out; i++;} return;} void add_digit(char a,char b,char carry_in,char* c,char* carry_out) { *c=(a+b+carry_in)%10; *carry_out=(a+b+carry_in)/10; return;} void display(char* a,char* b,char* c,int maxdigit) { lineprint(' ',a,maxdigit); lineprint('+',b,maxdigit); linedraw('-',maxdigit+1); lineprint(' ',c,maxdigit); return;} void lineprint(char c,char* line,int maxdigit) { int i,maxdigitlimit; maxdigitlimit=maxdigit-1; printf("%c",c); for(i=maxdigitlimit;i>=0;i--){ printf("%1d",line[i]); } printf("\n"); return;} void linedraw(char c,int length) { int i; for(i=0;i<length;i++) printf("%c",c); printf("\n"); return;}

  • javaプログラムの作り方

    class HTMLparam extends IO_Data_D { String s; int max_lean; Applet a; HTMLparam(int _max_lean, String _s, Applet _a) { max_lean = _max_lean; s = _s ; a = _a;} //-------------------------------------- Object getParam() { String param; char separated[][]; for(int i=0; i<max_lean; i++) { param = a.getParameter( s + (i+1) ); for(int j=0; j<max_lean; j++) { if(param != null ){ separated[][] = new char [max_lean][ param.length() ]; ???????????????????????????; } } return ; } } すごい初歩的な質問で申し訳ありません。いまいちキャストの仕方がよくわかっていません。質問というのは、param = a.getParameter( s + (i+1) );でparamに文字列が入ります。max_leanの行数文の文字列を文字配列にして文字を管理し、オブジェクトでリターンしたいのですが、どのように作っていいのかわかりません。教えていただけないでしょうか?

  • C言語計算プログラム

    Cの計算プログラム 下のプログラムを (1)上位桁の不要な0を表示しない (2)3つの数を計算できるようにする (3)0が入力されるまでは入力を受け付けて加算を繰り返す プログラムに改造する方法を教えてください。 #include <stdio.h> #define MAXDIGIT 70 void reset(char*,int); void input(char*,int); void add(char*,char*,char*,int); void add_digit(char ,char ,char ,char* ,char* ); void display(char* ,char* ,char* ,int ); void lineprint(char ,char* ,int ); void linedraw(char ,int ); int main(void) { char a[MAXDIGIT],b[MAXDIGIT],c[MAXDIGIT]; reset(a,MAXDIGIT); reset(b,MAXDIGIT); reset(c,MAXDIGIT); input(a,MAXDIGIT); input(b,MAXDIGIT); add(a,b,c,MAXDIGIT); display(a,b,c,MAXDIGIT); return 0;} void reset(char* buf,int maxdigit) { int i; for(i=0;i<maxdigit;i++) buf[i]=0; return;} void input(char* buf,int maxdigit) { char str[MAXDIGIT]; int i,j; printf("input data:"); scanf("%s",str); i=0; while(str[i]!='\0') i++; j=0; while(i>0){ buf[j]=str[i-1]-'0'; j++; i--; } return;} void add(char* a,char* b,char* c,int maxdigit) { int i; char carry_in,carry_out; i=0; carry_in=0; while(i<maxdigit) { add_digit(a[i],b[i],carry_in,&c[i],&carry_out); carry_in=carry_out; i++;} return;} void add_digit(char a,char b,char carry_in,char* c,char* carry_out) { *c=(a+b+carry_in)%10; *carry_out=(a+b+carry_in)/10; return;} void display(char* a,char* b,char* c,int maxdigit) { lineprint(' ',a,maxdigit); lineprint('+',b,maxdigit); linedraw('-',maxdigit+1); lineprint(' ',c,maxdigit); return;} void lineprint(char c,char* line,int maxdigit) { int i,maxdigitlimit; maxdigitlimit=maxdigit-1; printf("%c",c); for(i=maxdigitlimit;i>=0;i--){ printf("%1d",line[i]); } printf("\n"); return;} void linedraw(char c,int length) { int i; for(i=0;i<length;i++) printf("%c",c); printf("\n"); return;}

  • javaのコンパイルができません。

    コンパイルができません エラーの内容とソースコードは次です Microsoft Windows [Version 6.0.6002] Copyright (c) 2006 Microsoft Corporation. All rights reserved. C:\Users\j1409061\Documents\java\MeikaiJava>javac SR091409061.java SR091409061.java:7: 式の開始が不正です。 const int MAX_INT = 2147483647; ^ SR091409061.java:8: 式の開始が不正です。 const int BUFFER_SIZE = 100; ^ SR091409061.java:9: ';' がありません。 int main();{ ^ SR091409061.java:16: ']' がありません。 char buf[BUFFER_SIZE]; ^ SR091409061.java:16: 式の開始が不正です。 char buf[BUFFER_SIZE]; ^ SR091409061.java:22: 式の開始が不正です。 n = sscanf(buf, "%d %c", &data, &c); ^ SR091409061.java:22: 式の開始が不正です。 n = sscanf(buf, "%d %c", &data, &c); ^ SR091409061.java:73: 式の開始が不正です。 n = sscanf(buf+i, "%d", &data); ^ SR091409061.java:96: class、interface、または enum がありません。 } ^ エラー 9 個 C:\Users\j1409061\Documents\java\MeikaiJava> //最大値と最小値を求めよう // C:\Users\j1409061\Documents\java\MeikaiJava\SR091409061.java class SR091409061 { public static void main(String args[]) { Scanner stdIn = new Scanner(System.in); const int MAX_INT = 2147483647; const int BUFFER_SIZE = 100; int main();{ /* 変数を定義、初期化 */ int data; int max = -1; int min = MAX_INT; bool data_exist = false; int i, n; char buf[BUFFER_SIZE]; printf("Please input data : "); while(true) { /* データ(1行分読み込み) */ fgets(buf, BUFFER_SIZE, stdin); /* データ取り出しと計算 */ n = sscanf(buf, "%d %c", &data, &c); if( ( n == -1 ) || ( n == 0 ) ) { break; } else if (n == 1) { // the number of data is 1. data_exist = true; data = abs( data ); if(max < data){ /* maxを変更 */ max = data; } if(min > data){ /* minを変更 */ min = data; } } else if (n == 2) { // the number of data is larger than 2. i = 0; while (true) { data_exist = true; data = abs( data ); if(max < data){ /* maxを変更 */ max = data; } if(min > data){ /* minを変更 */ min = data; } // 空白文字を読み飛ばす while (true) { if(buf[i] == ' ') { i++; } else { break; } } // 数字(0から9)を読み飛ばす while (true) { if( ( buf[i] >= '0' ) && ( buf[i] <= '9' ) ) { i++; } else { break; } } // 行末なら終える if(buf[i] == '\n') { break; } // データ読み込み.読み込みに成功したら次の文字へ(i++), 失敗したら終える(break). n = sscanf(buf+i, "%d", &data); if(n == 0) { break; } i++; } } if(n == 0) { break; } } /* 最大値, 最小値を出力 */ if (!data_exist) { printf("No data.\n"); } else { printf("Max = %d\n",max); printf("Min = %d\n",min); } return 0; } } } } よろしくお願いします

  • javaプログラミング

    javaとYahooのWebサービスを利用して、検索結果のxmlを取り出し、 ○○.xmlという引数を与えて、結果を書き出そうとしていますが、 以下のプログラムだと文字(日本語)が化けてしまいます。 どうにかして文字化けせず取り出すことはできないでしょうか。 よろしくおねがいします。 import java.io.BufferedWriter; import java.io.FileWriter; import java.io.InputStream; import java.net.URL; public class YahooWebServiceExample { public static void main(String[] args) { String request = "http://api.search.yahoo.co.jp/WebSearchService/V1/webSearch? appid=web_research&query=%e6%b2%96%e7%b8%84&results=2"; try { // ファイル出力ストリームを取得(第二引数) BufferedWriter bw = new BufferedWriter(new FileWriter(args[0])); URL url = new URL(request); InputStream in = url.openStream(); byte[] buf = new byte[1024]; int len; while ((len = in.read(buf)) > 0) { for (int i = 0; i < len; i++) { System.out.print((char) buf[i]); bw.write(buf[i]); } } in.close(); bw.close(); } catch (Exception e) { System.out.println("Web services request failed"); } } }

    • ベストアンサー
    • Java
  • javaのRandomで『a~z』までの乱数を表示させたいですが・・・。

    『a~z』の英小文字をランダムで表示させ、さらにint型変数countを『0~9』までランダムに発生させて取得した数だけ『a~z』をランダムに表示させたいのですが、表示結果が(例)aaaaa・・・ となってしまいます。本当は、acyxd・・・とランダムに表示させたいのですがどうすれば、よいでしょうか? import java.util.*; import java.io.*; class CharCheck{  public char charRandom(){ int n; char c = ' '; Random ran = new Random(); while(true){  n = ran.nextInt(123); if(n >= 97 && n <= 122){  c = (char)n;    break; }  }  return c; } public class RandomTest extends CharCheck{  public static void main(String args[]){   char ch[] = new char[10]; int count = 0; CharCheck ChChk = new CharCheck(); Random ran = new Random();   komoji = ran.nextInt(9);//英小文字をいくつ表示するかランダムで決める? (1以上とする) if(count == 0){    count++; } for(int i=0; i<count; i++){ ch[i] = ChChk.charRandom();    System.out.println(ch[i]); } } }

    • ベストアンサー
    • Java
  • java setterとgetterについて

    データをセットしたファイルとは別のファイルからゲットしたいの ですが、できるのでしょうか? できるのでしたら、方法を教えてください。 具体的には下記のような感じです。 (かなり端折っている&あまり理解できていないので  おかしいsrcかもしれませんが、  やりたいことは、A.javaでセットした値をB.javaでゲットしたい  のです・・・。) 宜しくお願いいたします。 ■Data.java public class Data{   private String mojiData;   public Data(String _mojiData){     mojiData = _mojiData;   }   public void setMojiData(String _mojidata){     mojiData = _mojiData;   }   public void getMojiData(){     return mojiData;   } } ■A.java public class A extend JApplet{   public void init(){     Data[] data = new Data[2];     param[0] = a;     param[1] = i;     for(int i=0; i<2; i++){       data[i] = new Data("");       data[i].setMojiData(param);     }   } } ■B.java public class B extend JApplet{   String strData = new String[2];   public void ren(){     Data[] data;     for(int i=0; i<2; i++){       String strData[i] = data[i].getMojiData();     }   } }

    • ベストアンサー
    • Java
  • JAVA 引数の引数の取得について

    JAVA初心者です。的を得ていない書き込みをするかもしれませんが ご勘弁ください。今JUNITであるクラスのあるメソッド(MethodA)をチェックする テストプログラムを作成しております。 MethodA: public File MethodA(String name, File A) { int i = name.substring(0, i); String ret = name.substring(0, i + 1); return new File(A, ret); この場合に戻り値として返される引数の部分 「return new File(A, ret);」 の「A」と「ret」の値をJUNITで確認したいのですが、アイデアを 頂けますと大変幸いです。 また、戻り値の「return new File(A, ret);」に 「new」とついているのはなぜでしょうか?? 基本的な質問で大変申し訳ございませんが、よろしくお願いします。

    • ベストアンサー
    • Java
  • ポインタのポインタの使い方

    文字列の途中からの部分を表示させる場合もあって、途中からの 位置というのをcahr**型の配列に記憶させることにしました。 ポインタとnewがよく分からないから、それに近いサンプルを 作って実験しているところです。 #include <iostream.h> main() {  char selected[][6] = {"full", "nomal", "short"};  char *buf;  char **p;  buf = new char[500];  strcpy(buf, ",東京都,千代田区,九段南");  p = new char*[3];  for(unsigned int i=0, j=0; i<strlen(buf); i++)  {   if(buf[i] == ',')p[j++] = &buf[i+1];  }  for(int i=0; i<3; i++)  {   cout << selected[i] << "-" << p[i] << endl;  }  delete [] buf;  delete [] p; } 結果は full-東京都,千代田区,九段南 nomal-千代田区,九段南 short-九段南 で、問題なさそうに見えるけど心配だから質問しました。 このソースに問題はないですか? 得に、 char **p; と p = new char*[3]; と p[j++] = &buf[i+1]; と delete [] buf; が心配です。

  • 配列の配列をmemcpyやmemcmpしたいです

    【環境】WindowsXP(SP2)、VisualStudio2005++(MFC) タイトルの通りなんですが、配列の配列を比較したりコピーしたいのですが、以下に質問を3つ記載させていただきますので、どなたかご教授お願いいたしますm(__)m 1.宣言と初期化について char **buf; buf = new char*[3200]; for(int i=0; i < 3200; i++) { buf[i] = new char[4]; } これで、buf[1]、buf[2]、buf[3]、buf[4]に、それぞれ3200のchar型の配列が宣言された事になりますでしょうか? ※buf[4][3200] なのか buf[3200][4]なのかよく分からないです。 2.上記の方法で定義した2つの配列(bufとtmp)の比較 for(int i =0; i < 4; i++) { memcmp (buf[i], tmp[i], sizeof(tmp[i])); } これで比較出来ますでしょうか? 3.上記の方法で定義した2つの配列(bufとtmp)のコピー for(int i =0; i < 4; i++) { memcpy_s(buf[i], sizeof(buf[i]), tmp[i], 3200 * sizeof(char)); } これではバッファオーバーランエラーが発生してしまうのですが、どこがおかしいでしょうか? 以上3点、初心者の質問なので意味が分からないような箇所があるとは思いますが、どうかご教授お願いいたしますm(__)m  

専門家に質問してみよう