001package com.streamconverter.command.impl.charcode;
002
003import com.streamconverter.command.AbstractStreamCommand;
004import java.io.IOException;
005import java.io.InputStream;
006import java.io.InputStreamReader;
007import java.io.OutputStream;
008import java.io.OutputStreamWriter;
009import java.nio.charset.Charset;
010import java.util.Objects;
011
012/**
013 * Converts the character encoding of a stream from one encoding to another.
014 *
015 * <p>This class extends the AbstractStreamCommand and implements the conversion of character
016 * encodings.
017 */
018// BEGIN CharacterConvertCommand.java
019public class CharacterConvertCommand extends AbstractStreamCommand {
020  private String from;
021  private String to;
022
023  /**
024   * Constructor to initialize the character encodings for conversion.
025   *
026   * @param from The source character encoding.
027   * @param to The target character encoding.
028   * @throws IllegalArgumentException if the specified character encodings are not supported.
029   */
030  private CharacterConvertCommand(String from, String to) {
031    this.from = from;
032    this.to = to;
033  }
034
035  /**
036   * Factory method to create a CharacterConvertCommand.
037   *
038   * @param from The source character encoding.
039   * @param to The target character encoding.
040   * @return a new CharacterConvertCommand instance
041   * @throws IllegalArgumentException if the specified character encodings are not supported.
042   */
043  public static CharacterConvertCommand create(String from, String to) {
044    Objects.requireNonNull(from);
045    Objects.requireNonNull(to);
046    if (!Charset.isSupported(from)) {
047      throw new IllegalArgumentException("変換元文字コードがサポートされていません");
048    }
049    if (!Charset.isSupported(to)) {
050      throw new IllegalArgumentException("変換先文字コードがサポートされていません");
051    }
052    return new CharacterConvertCommand(from, to);
053  }
054
055  /**
056   * Executes the character encoding conversion on the provided input stream and writes the result
057   * to the output stream.
058   *
059   * @param inputStream The input stream to read data from.
060   * @param outputStream The output stream to write data to.
061   * @throws IOException If an I/O error occurs during the execution of the command.
062   */
063  @Override
064  public void execute(InputStream inputStream, OutputStream outputStream) throws IOException {
065    Objects.requireNonNull(inputStream);
066    Objects.requireNonNull(outputStream);
067
068    // 省メモリストリーミング文字コード変換
069    try (InputStreamReader reader = new InputStreamReader(inputStream, this.from);
070        OutputStreamWriter writer = new OutputStreamWriter(outputStream, this.to); ) {
071
072      // transferTo()は大容量データでメモリを大量消費するため、
073      // 固定サイズバッファでストリーミング処理を実装
074      char[] buffer = new char[8192]; // 8KB char buffer (16KB memory)
075      int charsRead;
076
077      while ((charsRead = reader.read(buffer)) != -1) {
078        writer.write(buffer, 0, charsRead);
079        writer.flush(); // 即座に出力してメモリを解放
080      }
081    }
082  }
083}