行分解器
mkm読み込み向けに途中まで作ったmqoローダの部品を切り出してきた。
テキストフォーマットのファイルの読み込みはだいたい行毎に
読み込んでトークンにバラす処理になるのだが
フォーマット毎に一から作るのも面倒だし、
モデルデータにboost::spritとかを使うのも微妙なので作った。
\nがくるまでをベクタに突っ込んで、
splitが呼ばれたら行をトークンに区切る。
ダブルクォートが来たら次のダブルクォートが来るまでは通常の区切りを休止する。
トークンは、\0で終端された文字列を期待すると読み込んだ行からさらに
コピーして\0でフタしてやる必要が出てよろしくないので
const char*で先頭と\0の来るべき位置を指してやることにした
(boost::spritのパクリ)
。
ポリゴンデータをバラすのにstd::stringは向いてないのだが、
strlen, strcmpがなんか嫌なので作った。
あとatoi, atofも隠した。
main.cpp
#include <iostream> #include <fstream> #include "linereader.h" struct Delemeter { bool operator()(char letter) { switch(letter) { case ' ': case '\t': // fall through case '\r': // fall through case '(': // fall through case ')': // fall through return true; default: return false; } } }; int main(int argc, char **argv) { if(argc<2){ std::cout << "require argment" << std::endl; return 1; } std::ifstream io(argv[1], std::ios::binary); if(!io){ return 2; } // mkm読み込み実験 LineReader<Delemeter> reader(io); while(reader.nextLine()){ reader.split(); if(reader.get(0)=="name"){ std::cout << "name: " << reader.get(2) << std::endl; } else if(reader.get(0)=="0"){ std::cout << "0 frame: " << reader.getFloat(1) << ',' << reader.getFloat(2) << ',' << reader.getFloat(3) << std::endl; } } return 0; }
linereader.h
#ifndef _LINEREADER_H #define _LINEREADER_H #include <fstream> #include <cassert> #include <vector> #include <stdlib.h> //------------------------------------------------------------// // string utility //------------------------------------------------------------// struct CharacterSequence { char *head; char *tail; CharacterSequence(char *_head, char *_tail) : head(_head), tail(_tail) {} bool operator==(const char *rhs)const { for(char *p=head; p!=tail; ++p, ++rhs) { if(*p!=*rhs) { return false; } } return *rhs=='\0'; } bool operator!=(const char *rhs)const { return !(*this==rhs); } int bytes(){ return tail-head; } }; inline std::ostream& operator<<(std::ostream& os, const CharacterSequence &rhs) { return os << '"' << std::string(rhs.head, rhs.tail) << '"'; } //------------------------------------------------------------// // tokenizer //------------------------------------------------------------// template<typename DELEMETER> class LineReader { std::istream &io_; std::vector<char> lineBuffer_; std::vector<char*> heads_; std::vector<char*> tails_; int lineCount_; int offset_; public: LineReader(std::istream &io) : io_(io), lineCount_(0) {} bool nextLine() { if(io_.eof()) return false; lineBuffer_.clear(); heads_.clear(); tails_.clear(); offset_=0; readline_(); if(io_.eof() && lineBuffer_.empty()){ return false; } ++lineCount_; return true; } int lineCount(){ return lineCount_; } int split(){ DELEMETER isDelemeter; size_t pos=0; size_t end=lineBuffer_.size(); while(pos<end) { // skip space while(pos<end && isDelemeter(lineBuffer_[pos])){ ++pos; } if(pos>=end) { break; } if(lineBuffer_[pos]=='"'){ // quoted string ++pos; heads_.push_back(&lineBuffer_[pos]); while(lineBuffer_[pos]!='"'){ ++pos; if(pos>=end){ assert(false); break; } } tails_.push_back(&lineBuffer_[pos]); ++pos; } else{ heads_.push_back(&lineBuffer_[pos]); while(pos<end && !isDelemeter(lineBuffer_[pos])){ ++pos; } tails_.push_back(&lineBuffer_[pos]); } } return static_cast<int>(heads_.size()); } int splitCount(){ return static_cast<int>(heads_.size())-offset_; } void shift(int count) { offset_+=count; } CharacterSequence get(int _index) { if(heads_.empty()){ return CharacterSequence(NULL, NULL); } else{ int index=offset_+_index; return CharacterSequence(heads_[index], tails_[index]); } } int getInt(int _index) { int index=offset_+_index; return atoi(heads_[index]); } double getFloat(int _index) { int index=offset_+_index; return atof(heads_[index]); } CharacterSequence getLine() { if(lineBuffer_.empty()){ return CharacterSequence(NULL, NULL); } else{ return CharacterSequence(&lineBuffer_[0], (&lineBuffer_.back())+1); } } private: void readline_() { while(!io_.eof()) { char letter=io_.get(); switch(letter){ case '\r': continue; case '\n': return; default: lineBuffer_.push_back(letter); } } } }; //------------------------------------------------------------// // token delemeter //------------------------------------------------------------// struct SpaceDelemeter { bool operator()(char letter) { switch(letter) { case ' ': case '\t': // fall through case '\r': // fall through return true; default: return false; } } }; #endif // _SCENE_H
例によって本題に入る前に手間がかかる・・・