j2objc(0.9.3)において、BufferedInputStream#readでIOException

Javaで以下のようなZip解凍用のソースコードを書いた。

```java:ZipUtil.java
public static boolean unzip(String zipfile, String dstDir) {
	// テンポラリディレクトリを作成する。
	File baseDir = new File(dstDir);
	if (!baseDir.mkdirs()) {
		return false;
	}

	// Zip ファイルから ZipEntry を一つずつ取り出し、ファイルに保存していく。
	ZipFile zipFile = null;
	try {
		zipFile = new ZipFile(zipfile);
		Enumeration<? extends ZipEntry> entries = zipFile.entries();
		while (entries.hasMoreElements()) {
			ZipEntry ze = entries.nextElement();

			// 出力先ファイル
			File outFile = new File(baseDir, ze.getName());
			if (ze.isDirectory()) {
				// ZipEntry がディレクトリの場合はディレクトリを作成。
				outFile.mkdirs();
			} else {

				BufferedInputStream bis = null;
				BufferedOutputStream bos = null;
				try {
					InputStream is = zipFile.getInputStream(ze);
					bis = new BufferedInputStream(is);

					if (!outFile.getParentFile().exists()) {
						// ディレクトリを作成しておく
						outFile.getParentFile().mkdirs();
					}
					bos = new BufferedOutputStream(new FileOutputStream(
							outFile));
					int len;
					while ((len = bis.available()) > 0) {
						byte[] bs = new byte[len];
						bis.read(bs);
						bos.write(bs);
					}
				} catch (FileNotFoundException e) {
					throw e;
				} catch (IOException e) {
					throw e;
				} finally {
					if (bis != null) {
						try {
							bis.close();
						} catch (IOException e) {
						}
					}
					if (bos != null) {
						try {
							bos.close();
						} catch (IOException e) {
						}
					}
				}
			}
		}
		return true;

	} catch (IOException e) {
		// TODO Auto-generated catch block
		e.printStackTrace();
	}

	return false;
}
```

当然Javaでの動作確認はＯＫ．
j2objcでのコンパイルもＯＫ．
変換後のObjcコードはこちら。

```objc:ZipUtil.m
+ (BOOL)unzipWithNSString:(NSString *)zipfile
             withNSString:(NSString *)dstDir {
  JavaIoFile *baseDir = [[JavaIoFile alloc] initWithNSString:dstDir];
  if (![baseDir mkdirs]) {
    return NO;
  }
  JavaUtilZipZipFile *zipFile = nil;
  @try {
    zipFile = [[JavaUtilZipZipFile alloc] initWithNSString:zipfile];
    id<JavaUtilEnumeration> entries = [zipFile entries];
    while ([((id<JavaUtilEnumeration>) nil_chk(entries)) hasMoreElements]) {
      JavaUtilZipZipEntry *ze = [entries nextElement];
      JavaIoFile *outFile = [[JavaIoFile alloc] initWithJavaIoFile:baseDir withNSString:[((JavaUtilZipZipEntry *) nil_chk(ze)) getName]];
      if ([ze isDirectory]) {
        [outFile mkdirs];
      }
      else {
        JavaIoBufferedInputStream *bis = nil;
        JavaIoBufferedOutputStream *bos = nil;
        @try {
          JavaIoInputStream *is = [zipFile getInputStreamWithJavaUtilZipZipEntry:ze];
          bis = [[JavaIoBufferedInputStream alloc] initWithJavaIoInputStream:is];
          if (![((JavaIoFile *) nil_chk([outFile getParentFile])) exists]) {
            [((JavaIoFile *) nil_chk([outFile getParentFile])) mkdirs];
          }
          bos = [[JavaIoBufferedOutputStream alloc] initWithJavaIoOutputStream:[[JavaIoFileOutputStream alloc] initWithJavaIoFile:outFile]];
          int len;
          while ((len = [bis available]) > 0) {
            IOSByteArray *bs = [IOSByteArray arrayWithLength:len];
            [bis readWithByteArray:bs];
            [bos writeWithByteArray:bs];
          }
        }
        @catch (JavaIoFileNotFoundException *e) {
          @throw e;
        }
        @catch (JavaIoIOException *e) {
          @throw e;
        }
        @finally {
          if (bis != nil) {
            @try {
              [bis close];
            }
            @catch (JavaIoIOException *e) {
            }
          }
          if (bos != nil) {
            @try {
              [bos close];
            }
            @catch (JavaIoIOException *e) {
            }
          }
        }
      }
    }
    return YES;
  }
  @catch (JavaIoIOException *e) {
    [((JavaIoIOException *) nil_chk(e)) printStackTrace];
  }
  return NO;
}
```

しかしいざ実行すると、それぞれ以下の行に該当するところで、IOExceptionを吐いて落ちる。

```java:ZipUtil.java-エラー行
bis.read(bs);
```

```objc:ZipUtil.m-エラー行
[bis readWithByteArray:bs];
```

調べたが、ググっても情報は無し。
仕方ないので、Javaを次のように書き換えてみた。

```java:ZipUtil修正版.java
public static boolean unzip(String zipfile, String dstDir) {
	// テンポラリディレクトリを作成する。
	File baseDir = new File(dstDir);
	if (!baseDir.mkdirs()) {
		return false;
	}
	final int BUFFER_SIZE = 1024;

	try {
		BufferedOutputStream dest = null;
		FileInputStream fis = new FileInputStream(new File(zipfile));
		ZipInputStream zis = new ZipInputStream(
				new BufferedInputStream(fis));
		ZipEntry entry;
		File destFile;
		while ((entry = zis.getNextEntry()) != null) {

			destFile = new File(baseDir, entry.getName());
			if (entry.isDirectory()) {
				destFile.mkdirs();
				continue;
			} else {
				int count;
				byte data[] = new byte[BUFFER_SIZE];

				destFile.getParentFile().mkdirs();

				FileOutputStream fos = new FileOutputStream(destFile);
				dest = new BufferedOutputStream(fos, BUFFER_SIZE);
				while ((count = zis.read(data, 0, BUFFER_SIZE)) != -1) {
					dest.write(data, 0, count);
				}

				dest.flush();
				dest.close();
				fos.close();
			}
		}
		zis.close();
		fis.close();
		return true;

	} catch (FileNotFoundException e) {
		e.printStackTrace();
		LogD(e.getMessage());
	} catch (IOException e) {
		e.printStackTrace();
		LogD(e.getMessage());
	}

	return false;
}
```

変換後のObjective-Cのコードはこちら。

```objc:ZipUtil修正版.m
+ (BOOL)unzipWithNSString:(NSString *)zipfile
             withNSString:(NSString *)dstDir {
  JavaIoFile *baseDir = [[JavaIoFile alloc] initWithNSString:dstDir];
  if (![baseDir mkdirs]) {
    return NO;
  }
  int BUFFER_SIZE = 1024;
  @try {
    JavaIoBufferedOutputStream *dest = nil;
    JavaIoFileInputStream *fis = [[JavaIoFileInputStream alloc] initWithJavaIoFile:[[JavaIoFile alloc] initWithNSString:zipfile]];
    JavaUtilZipZipInputStream *zis = [[JavaUtilZipZipInputStream alloc] initWithJavaIoInputStream:[[JavaIoBufferedInputStream alloc] initWithJavaIoInputStream:fis]];
    JavaUtilZipZipEntry *entry_;
    JavaIoFile *destFile;
    while ((entry_ = [zis getNextEntry]) != nil) {
      destFile = [[JavaIoFile alloc] initWithJavaIoFile:baseDir withNSString:[((JavaUtilZipZipEntry *) nil_chk(entry_)) getName]];
      if ([entry_ isDirectory]) {
        [destFile mkdirs];
        continue;
      }
      else {
        int count;
        IOSByteArray *data = [IOSByteArray arrayWithLength:BUFFER_SIZE];
        [((JavaIoFile *) nil_chk([destFile getParentFile])) mkdirs];
        JavaIoFileOutputStream *fos = [[JavaIoFileOutputStream alloc] initWithJavaIoFile:destFile];
        dest = [[JavaIoBufferedOutputStream alloc] initWithJavaIoOutputStream:fos withInt:BUFFER_SIZE];
        while ((count = [zis readWithByteArray:data withInt:0 withInt:BUFFER_SIZE]) != -1) {
          [dest writeWithByteArray:data withInt:0 withInt:count];
        }
        [dest flush];
        [dest close];
        [fos close];
      }
    }
    [zis close];
    [fis close];
    return YES;
  }
  @catch (JavaIoFileNotFoundException *e) {
    [((JavaIoFileNotFoundException *) nil_chk(e)) printStackTrace];
    [JpCoCybirdEscapeEngineLibUtilLibUtil LogDWithNSString:[e getMessage]];
  }
  @catch (JavaIoIOException *e) {
    [((JavaIoIOException *) nil_chk(e)) printStackTrace];
    [JpCoCybirdEscapeEngineLibUtilLibUtil LogDWithNSString:[e getMessage]];
  }
  return NO;
}
```

つまり、BufferedInputStream#availableでサイズを取ってそのサイズ分byte配列を確保して一気に読み込んでいたのを、固定サイズ[BUFFER_SIZE]で回しながら読む方法に変えたのだ。
そしたら、無事に実行できた。
変換後のソースの違いは、```readWithByteArray```か、```readWithByteArray: withInt: withInt```かの違い。

allocできる限界のサイズがあるんだろうか？？

気が向いたらj2objc-discussグループにも報告しておこう･･･