2016年8月2日火曜日

Visual Studio 2015 C++ で splitpath(関連のライブラリ)が正しく動作しない

いまだに Win32 な開発をするケースがあります。
バージョンアップのついでに、Visual Studio 2008の環境で構築されたプロジェクトを Visual Studio 2015 に移行してビルドしてみました。
とりあえず、動くようになるまでの手続きはさほどややこしくなかったんですけどね。

ファイル名の処理で、「管理表.xls」とか「申請書.doc」なんかでファイル名が正しく処理されなくなる!

なんとも懐かしい、Shift-JIS の \x5c 問題です。

いや、デグレードは困りますよ、マイクロソフトさん!

Visual Studio 2015 Update2 なんですが、ふと facebookを見ると、Update3 のニュースが!
で、MSDN見に行ってみると、Update3が出てるんですね。
んでも、サブスクリプションが期限切れでダウンロードできませんでした。 orz

かくなる上は、ということで、問題となっていた splitpath の部分だけ自前で書くことにしましたよ。
時間かかったけど、リリースできたからいいや。

ということで、ソース書いておきますね。(使ってないモジュールも入ってるけど)

#define IS_MBS_LEAD(c) (((0x81 <= ((unsigned char)(c))) && (((unsigned char)(c)) <= 0x9F)) || ((0xE0 <= ((unsigned char)(c))) && (((unsigned char)(c)) <= 0xFC) ))
#define IS_MBS_TRAIL(c) ((0x7F != (unsigned char)(c)) && (0x40 <= ((unsigned char)(c))) && (((unsigned char)(c)) <= 0xFC))
static const char *previousChar(const char *top, const char *pos)
{
 pos--;
 if (IS_MBS_TRAIL(*pos))
 {
  if (top < pos)
  {
   if (IS_MBS_LEAD(*(pos - 1)))
   {
    return pos - 1;
   }
  }
 }
 return pos;
}

static const char *nextChar(const char *pos, const char *tail)
{
 pos++;
 if (IS_MBS_LEAD(*pos))
 {
  if (pos < tail)
  {
   if (IS_MBS_TRAIL(*(pos + 1)))
   {
    return pos + 1;
   }
  }
 }
 return pos;
}

void SplitPath(const char *path, char *drive, size_t drive_length, char *dir, size_t dir_length, char *fname, size_t fname_length, char *ext, size_t ext_length)
{
 const char *tail = &path[strlen(path)];
 const char *prev = tail;
 size_t length = 0;
 bool fext = false;
 bool ffname = false;
 // EXT
 const char *ext_tail = tail;
 const char *ext_top = tail;
 const char *fname_tail = tail;
 const char *fname_top = tail;
 while ((prev = previousChar(path, prev)) != path)
 {
  if (*prev == '.') 
  {
   ext_top = prev;
   break;
  }
  // 拡張子のないファイルだった場合
  if ((*prev == '\\') || (*prev == '/') || (*prev == ':'))
  {
   prev++;
   break;
  }
 }
 // 拡張子が決定しているか
 const char *src;
 if (ext_top < ext_tail) 
 {
  if (ext != NULL) 
  {
   length = 0;
   src = ext_top;
   while ((src < ext_tail) && (length < fname_length))
   {
    *ext++ = *src++;
    length++;
   }
   *ext = '\0';
  }
  fname_tail = ext_top;
 }
 // ファイル名を取得
 if ((prev != path) && (*prev != '\\') && (*prev != '/') && (*prev != ':'))
 {
  do{
   prev = previousChar(path, prev);
   // 拡張子のないファイルだった場合
   if ((*prev == '\\') || (*prev == '/') || (*prev == ':'))
   {
    prev++;
    break;
   }
  } while (prev != path);
 }
 fname_top = prev;
 if(fname_top < fname_tail)
 {
  if (fname != NULL)
  {
   length = 0;
   src = fname_top;
   while ((src < fname_tail) && (length < fname_length))
   {
    *fname++ = *src++;
    length++;
   }
   *fname = '\0';
  }
 }

 const char *dir_tail = fname_top;
 const char *dir_top = path;
 const char *drive_tail = strchr(path, ':');
 // drive
 if (drive_tail != NULL)
 {
  if (drive != NULL) 
  {
   length = 0;
   src = path;
   while ((src <= drive_tail) && (length < drive_length))
   {
    *drive++ = *src++;
    length++;
   }
   *drive = '\0';
  }
  dir_top = drive_tail + 1;
 }
 if(dir_top < dir_tail)
 {
  if (dir != NULL) 
  {
   length = 0;
   src = dir_top;
   while ((src < dir_tail) && (length < dir_length))
   {
    *dir++ = *src++;
    length++;
   }
   *dir = '\0';
  }
 }
 return;
}

0 件のコメント:

コメントを投稿