2009/04/19(日)続・UOのジャーナル保存

UO をネタにプログラムで遊ぶ日記になってきた。

久しぶりに C を書きたくなったので、ミソな部分+αを書いてみた。
  • シングルバイトな<LF> を取り除いて
    • 諸悪の根源を除去
  • <CR> も邪魔なので取り除いて
  • ついでに <LF> が連続する場合も取り除いちゃう
というプログラム。

後は
  • UTF-16-LE な文字コードを UTF-8 か Shift-JIS に変換
    • マルチプラットフォームで文字コード変換できるライブラリってあるんかな
  • 処理結果をファイルに保存
    • 10行くらいの追加でとりあえず OK
すれば機能は十分。GUI が付けば完璧。やらんけど。

UO のジャーナルファイルは一度のゲームで数百KB 程度になるらしいので、一度に処理するバッファのサイズは 128KB くらいがちょうどいいのかなぁ。
#include <stdio.h>
#include <stdlib.h>
#include <strings.h>

int main(int argc, char **argv)
{
  char *file, *buf, *newbuf;
  int index, newindex, lfflag, lfappered, crflag;
  FILE *filep;
  size_t bufsize = 1024 * 128; /* 128KB でいいかな? */
  size_t gottenbuf;

  if (argc < 2) {
    fprintf(stderr, "Please indicate an UO\'s Journal.\n");
  }
  filep = fopen(argv[1], "r");
  if (!filep) {
    fprintf(stderr, "%s could not be opened.\n", argv[1]);
    exit(-1);
  }
  
  buf = malloc(sizeof(char) * bufsize);
  newbuf = malloc(sizeof(char) * bufsize);
  memset(newbuf, 0x00, bufsize);
  memset(buf, 0x00, bufsize);
  crflag = lfflag = 0;
  while (gottenbuf = fread(buf, sizeof(char), bufsize, filep)) {
    newindex = 0;
    for(index = 0; index < gottenbuf; index++) {
      if (buf[index] == 0x0d) {
	lfflag = 1;
      } else if (lfflag && buf[index] == 0x00) {
      /* 前のバイトが 0x0d かつ今見てるものが 0x00 なら 0x0d00 を挿入 */
	if(lfappered) {
        /* <LF> が連続している場合は読み飛ばす(何もしない) */
	  lfflag = 0;
	  lfappered = 0;
	} else {
	  newbuf[newindex] = 0x0d;
	  newindex++;
	  newbuf[newindex] = buf[index];
	  newindex++;
	  lfflag = 0;
          /* 一文字前は <LF> だったことを示すフラグを立てる */
	  lfappered = 1;
	}
      } else if (buf[index] == 0x0a) {
      /* <CR> は いらない子 */
	crflag = 1;
	lfappered = 0;
      } else if (crflag && buf[index] == 0x00) {
	crflag = 0;
	lfappered = 0; /* 実際はここでフラグ立ってることはないはず */
      } else {
      /* 改行文字以外の文字は普通に読み込む。かつ各フラグクリア */
	newbuf[newindex] = buf[index];
	newindex++;
	lfflag = 0;
	crflag = 0;
	lfappered = 0;
      }
    }
    fwrite(newbuf, sizeof(char), newindex, stdout);
    memset(newbuf, 0x00, bufsize);
    memset(buf, 0x00, bufsize);
  }
  close(filep);
  free(buf);
  free(newbuf);
}

自分でバッファを切り出して~とかバッファが変なところで切れた場合にどうするか~とか Perlだと考えないので面白かった。