o5mparser

作者: 微雨旧时歌丶 | 来源:发表于2018-01-30 16:59 被阅读0次

    解析o5m文件,在命令行中显示的c程序
    共741行
    下一步应整合、简化代码,规范接口,转化为C++程序

    // o5m_demo 2012-10-14 17:10
    // (c) 2012 Markus Weber, Nuernberg
    //
    // 这个程序从标准输入读取.o5m文件,并使用简单的文本格式将其内容写入标准输出。
    // 这是如何读取.o5m文件的一个实验性例子。
    //
    // 编译这个文件:
    // gcc o5m_demo.c -o o5m_demo
    //
    #define _FILE_OFFSET_BITS 64
    #include <inttypes.h>  //提供各种进制的转换宏
    #include <stdlib.h> //申请、释放内存空间
    #include <string.h>
    #include <stdio.h>
    #include <time.h>
    #include <unistd.h> // 是POSIX标准定义的unix类系统定义符号常量的头文件
    #include <fcntl.h> // 用来避免一些系统安全问题
    
    // typedef enum {false= 0,true= 1} bool; // 一般现在无需定义
    typedef uint8_t byte; // 一字节
    #if !__WIN32__
      #define O_BINARY 0
    #endif
    #define ONAME(i) \
      (i==0? "node": i==1? "way": i==2? "relation": "unknown object")
    
    static inline char *stpcpy0(char *dest, const char *src) {
      // 重新定义C99的stpcpy(),因为它在MinGW中是缺少的,
      // 而在Linux头文件中的声明似乎是错误的;
      while(*src!=0)
        *dest++= *src++;
      *dest= 0;
      return dest;
      }  // stpcpy0()
    
    static inline int strzcmp(const char* s1,const char* s2) {
      // 类似于strcmp(),这个过程比较两个字符串;
      // 在这里,要比较的字符数限于第二个字符串的长度;
      // 即,该过程可以用来识别长字符串s1内的短字符串s2;
      // s1[]: 第一个字符串;
      // s2[]: 与第一个字符串作比较的字符串;
      // 返回:
      // 0: 两个字符串是相同的;第一串可以比第二串长;
      // -1: 第一个字符串比第二个字母小;
      // 1: 第一个字符串比第二个字符串更大;
      while(*s1==*s2 && *s1!=0) { s1++; s2++; }
      if(*s2==0)
        return 0;
      return *(unsigned char*)s1 < *(unsigned char*)s2? -1: 1;
    }  // strzcmp()
    static inline char *strmcpy(char *dest, const char *src, size_t maxlen) {
      // 类似于strcpy(),这个过程 复制 一个字符串;
      // 这里是关心长度的, i.e. 如果太长,目标字符串将受到限制;
      // src[]: 要复制的源字符串;
      // maxlen: 目标字符串的最大长度(包括终止符null)
      // return:
      // dest[]: 目标字符串; 这也是函数的返回值
      char* d;
    
      if(maxlen==0)
    return dest;
      d= dest;
      while(--maxlen>0 && *src!=0)
        *d++= *src++;
      *d= 0;
      return dest;
      }  // end   strmcpy()
    #define strMcpy(d,s) strmcpy((d),(s),sizeof(d))
    
    
    //------------------------------------------------------------
    // Module pbf_   protobuf转换模块
    //------------------------------------------------------------
    
    // 这个模块提供了从protobuf格式到常规数字转换的程序;
    // 像往常一样,一个模块的所有标识符都有相同的前缀;
    // 此时是 'pbf'; 在全局可访问的对象中将有一个下划线
    // 在本模块之外不可访问的对象将有两个下划线
    // 私有和公共定义的部分用水平线分隔:----
    // 许多程序都有一个参数'pp';这里预期会有一个缓冲区指针
    // 这个指针会增加被转换的protobuf元素消耗的字节数
    
    //------------------------------------------------------------
    
    static inline uint32_t pbf_uint32(byte** pp) {
      // 获取无符号32位整数的值;
      // pp: see module header;
      byte* p;
      uint32_t i;
      uint32_t fac;
    
      p= *pp;
      i= *p;
      if((*p & 0x80)==0) {  // 只有一比特 (高位为0,代表只有一比特)
        (*pp)++; // 指针后移
    return i; // 返回获取的整数值
        }
      i&= 0x7f;
      fac= 0x80;
      while(*++p & 0x80) {  // 更多的比特
        i+= (*p & 0x7f)*fac; // 计算整数值
        fac<<= 7;
        }
      i+= *p++ *fac;
      *pp= p;
      return i;
      }  // pbf_uint32()
    
    static inline int32_t pbf_sint32(byte** pp) {
      // 获取有符号32位整数的值;
      // pp: see module header;
      byte* p;
      int32_t i;
      int32_t fac;
      int sig;
    
      p= *pp;
      i= *p;
      if((*p & 0x80)==0) {  // 只有一比特
        (*pp)++;
        if(i & 1)  // 负数
    return -1-(i>>1);
        else
    return i>>1;
        }
      sig= i & 1; // 符号位
      i= (i & 0x7e)>>1;
      fac= 0x40;
      while(*++p & 0x80) {  // more byte(s) will follow
        i+= (*p & 0x7f)*fac;
        fac<<= 7;
        }
      i+= *p++ *fac;
      *pp= p;
        if(sig)  // 负数
    return -1-i;
        else
    return i;
      }  // pbf_sint32()
    
    static inline uint64_t pbf_uint64(byte** pp) {
      // 获取无符号64位整数的值;
      // pp: see module header;
      byte* p;
      uint64_t i;
      uint64_t fac;
    
      p= *pp;
      i= *p;
      if((*p & 0x80)==0) {  // just one byte
        (*pp)++;
      return i;
        }
      i&= 0x7f;
      fac= 0x80;
      while(*++p & 0x80) {  // more byte(s) will follow
        i+= (*p & 0x7f)*fac;
        fac<<= 7;
        }
      i+= *p++ *fac;
      *pp= p;
      return i;
    }  // pbf_uint64()
    
    static inline int64_t pbf_sint64(byte** pp) {
      // 获取有符号64位整数的值;
      // pp: see module header;
      byte* p;
      int64_t i;
      int64_t fac;
      int sig;
    
      p= *pp;
      i= *p;
      if((*p & 0x80)==0) {  // just one byte
        (*pp)++;
        if(i & 1)  // negative
    return -1-(i>>1);
        else
    return i>>1;
        }
      sig= i & 1;
      i= (i & 0x7e)>>1;
      fac= 0x40;
      while(*++p & 0x80) {  // more byte(s) will follow
        i+= (*p & 0x7f)*fac;
        fac<<= 7;
        }
      i+= *p++ *fac;
      *pp= p;
        if(sig)  // negative
    return -1-i;
        else
    return i;
      }  // pbf_sint64()
    
    //------------------------------------------------------------
    // end   Module pbf_   protobuf转换模块
    //------------------------------------------------------------
    
    
    
    //------------------------------------------------------------
    // Module read_   OSM文件读取模块
    //------------------------------------------------------------
    
    // 本模块提供缓冲读取标准输入的程序;
    // 像往常一样,一个模块的所有标识符都有相同的前缀;
    // 此时是 'read'; 在全局可访问的对象中将有一个下划线
    // 在本模块之外不可访问的对象将有两个下划线
    // 私有和公共定义的部分用水平线分隔:----
    #define read_PREFETCH ((32+3)*1024*1024) // (prefetch)预取 35MB
      // 每次调用 read_input() 后缓冲区中可用的字节数;
    #define read__bufM (read_PREFETCH*5)  // 缓冲区的长度 35MBx5
      // 每次调用 read_input() 后缓冲区中可用的字节数;
    typedef struct {  // 成员可能无法从外部访问
      FILE* fi;  // 文件流
      off_t jumppos;  // position to jump to; -1: invalid
    
      int64_t counter;
        // 字节计数器获取输入文件中的读取位置;
      char filename[100];
      bool eof;  // 输文件结尾的标志
      byte* bufp;  // buf[]中的指针
      byte* bufe;  // 指向在buf[]中有效输入结束的指针
      uint64_t bufferstart;
        // 表示读取缓冲区开始的哑变量
        // 与这个读信息结构的实例连接;
      } read_info_t;
    static bool read__jumplock= false;  // do not change .jumppos anymore;
    
    //------------------------------------------------------------
    
    static read_info_t* read_infop= NULL;
      // 目前使用的阅读信息结构, 即文件句柄
    #define read__buf ((byte*)&read_infop->bufferstart)
      // 文件输入缓冲区的起始地址
    static byte* read_bufp= NULL;  
      // 可能在read_input()再次调用之前增加到 read_PREFETCH 字节
    static byte* read_bufe= NULL;  // 可能不会从外部改变
    
    //------------------------------------------------------------
    
    static int read_open(const char* filename) {
      // 打开一个输入文件;
      // filename[]: 输入文件的路径和名称;
      //             ==NULL: 标准输入;
      // 返回: 0: 正常; !=0: 错误;
      // read_infop: 文件句柄;
      // 注意你应该在程序结束之前用read_close()关闭每个打开的文件
    
      // 保存当前处理的输入文件的状态 (if any)
      if(read_infop!=NULL) {
        read_infop->bufp= read_bufp;
        read_infop->bufp= read_bufe;
        }
    
      // 分配 文件句柄 及 输入缓冲区 的内存空间
      read_infop= (read_info_t*)malloc(sizeof(read_info_t)+read__bufM);
      if(read_infop==NULL) {
        fprintf(stderr,"osmconvert Error: could not get "
          "%i bytes of memory.\n",read__bufM);
    return 1;
        }
    
      // 初始化 read info 结构
      read_infop->fi= NULL;  // (default) file not opened
      strMcpy(read_infop->filename,filename);
      read_infop->eof= false;  // we are not at the end of input file
      read_infop->bufp= read_infop->bufe= read__buf;  // pointer in buf[]
        // pointer to the end of valid input in buf[]
      read_infop->counter= 0;
      read_infop->jumppos= 0;
        // 将文件的起始存储为默认跳转目的地
    
      // 设置与此文件相关联的模块全局变量
      read_bufp= read_infop->bufp;
      read_bufe= read_infop->bufe;
    
      // 打开文件
      fprintf(stderr,"Read-opening: %s\n",read_infop->filename);
    
      if(filename!=NULL) {  // 一个真实的文件应该被打开
        read_infop->fi= fopen(filename,"rb");
        if(read_infop->fi==NULL) {
          fprintf(stderr,
            "osmconvert Error: could not open input file: %.80s\n",
            read_infop->filename);
          free(read_infop); read_infop= NULL;
          read_bufp= read_bufe= NULL;
    return 1;
          }
        }  // end   一个真实的文件应该被打开
    return 0;
    }  // end   read_open()
    
    static void read_close() {
      // 关闭一个打开的文件;
      // read_infop: 将要关文件句柄;
      if(read_infop==NULL)  // 文件句柄不可用;
    return;
      fprintf(stderr,"Read-closing: %s\n",read_infop->filename);
      fclose(read_infop->fi);
      free(read_infop); read_infop= NULL;
      read_bufp= read_bufe= NULL;
      }  // end   read_close()
    static inline bool read_input() {
      // 从标准输入文件读取数据,使用内部缓冲;
      // 使数据在 read_bufp 可用;
      // 在调用此过程之前,必须调用 read_open() ;
      // read_bufp: 可用的下一个字节开始;
      //            可以由调用者增加到 read_bufe ;
      // read_bufe: 缓冲区中字节的结束;
      //            不能被调用者更改;
      // 在调用此过程之后, 在地址 read_bufp 中至少有 read_PREFETCH 字节可用
      //  - 有一个例外: 如果从标准输入中没有足够的可读取的字节, 
      // 缓冲区中文件结束后的剩余部分直到read_bufp + read_PREFETCH所有字节都将被设置为0x00
      int l,r;
    
      if(read_bufp+read_PREFETCH>=read_bufe) {  // 读缓冲区过低
        if(!read_infop->eof) {  // still bytes to read
          if(read_bufe>read_bufp) {  // 缓冲区中有剩余的字节
            memmove(read__buf,read_bufp,read_bufe-read_bufp);
              // move remaining bytes to start of buffer
            read_bufe= read__buf+(read_bufe-read_bufp);
              // protect the remaining bytes at buffer start
            }
          else  // 缓冲区中没有剩余字节
            read_bufe= read__buf;  // no bytes remaining to protect
            // add read bytes to debug counter
          read_bufp= read__buf;
          do {  // while buffer has not been filled
            l= (read__buf+read__bufM)-read_bufe-4;
              // number of bytes to read
              r= read(fileno(read_infop->fi),read_bufe,l); // 读l长度的数据保存到缓冲区,返回实际读入的长度
            if(r<=0) {  // no more bytes in the file
              read_infop->eof= true;
                // memorize that there we are at end of file
              l= (read__buf+read__bufM)-read_bufe;
                // remaining space in buffer
              if(l>read_PREFETCH) l= read_PREFETCH;
              memset(read_bufe,0,l);  // 2011-12-24
                // set remaining space up to prefetch bytes in buffer to 0
          break;
              }
            read_infop->counter+= r;
            read_bufe+= r;  // 设置新的数据结尾标志位置
            read_bufe[0]= 0; read_bufe[1]= 0;  // set 4 null-terminators
            read_bufe[2]= 0; read_bufe[3]= 0;
            } while(r<l);  // end   while buffer has not been filled
          }  // end   still bytes to read
        }  // end   read buffer is too low
      return read_infop->eof && read_bufp>=read_bufe;
      }  // end   read__input()
    
    //------------------------------------------------------------
    // end   Module read_   OSM文件读取模块
    //------------------------------------------------------------
    
    
    
    
    //------------------------------------------------------------
    // Module str_   字符串读取模块
    //------------------------------------------------------------
    
    // 此模块提供了从数据流对象中存储的字符串转换为c格式字符串的过程;
    // 像往常一样,一个模块的所有标识符都有相同的前缀,
    // 此时为 'str'; 在全局可访问的对象中将有一个下划线
    // 在本模块之外不可访问的对象将有两个下划线
    // 私有和公共定义的部分用水平线分隔:----
    
    #define str__tabM (15000+4000)
      // +4000是因为可能发生一个对象有很多 key/val 对或者 refroles 的情况
      // 它们没有被存储
    #define str__tabstrM 250  // 必须是< str__tab[]的行大小
    
    static char str__tab[str__tabM][256];
      // 字符串表 see o5m documentation ;
      // 行长度必须至少是 str__tabstrM+2 ;
      // 每一行包含一个双字符串; 
      // 两个字符串中的每一个都以零字节结尾,
      // 逻辑长度总共不超过 str__tabstrM 字节;
      // 这个数组的第一个 str__tabM 行被用作字符串的输入缓冲区;
    static int str__tabi= 0;
      // 在字符串表中最后输入元素的索引;
    static int str__tabn= 0;  // 字符串表中有效字符串的数量;
    
    //------------------------------------------------------------
    
    static inline void str_reset() {
      // 清空字符串表;
      // 必须在本模块的任何其他进程之前调用
      // 可能在任何字符串进程需要重启时调用;
      str__tabi= str__tabn= 0;
      }  // str_reset()
    
    static void str_read(byte** pp,char** s1p,char** s2p) {
      // 从标准输入缓冲中读取一个o5m格式的字符串(对),如. key/val;
      // 如果读取到一个字符串引用,则使用内部字符串表解释它;
      // 如果字符串总长度超过250个字符,则不使用引用(包括终止符为252);
      // pp: 缓冲指针的地址;
      //     这个指针将会增加被转换的protobuf元素消耗的字节数;
      // s2p: ==NULL: 读取的不是字符串对,而是单个字符串;
      // 返回:
      // *s1p,*s2p: 已读取的字符串的指针;
      char* p;
      int len1,len2;
      int ref;
      bool donotstore;  // 字符串“不存储标志”  2012-10-01
    
      p= (char*)*pp;
      if(*p==0) {  // 直接给出的字符串(对)
        p++;
        donotstore= false;
        #if 0  // 不使用,因为字符串不再是透明的
        if(*++p==(char)0xff) {  // 字符串有“不存储标志”  0xff是重置字节
          donotstore= true;
          p++;
          }  // 字符串有“不存储标志”
          #endif
        *s1p= p;
        len1= strlen(p); // 获取当前字符串长度
        p+= len1+1; // 指针后移到下一个字符串的起始地址
        if(s2p==NULL) {  // 单个字符串
          if(!donotstore && len1<=str__tabstrM) {
              // 单个字符串对于字符串表来说足够短
            stpcpy0(str__tab[str__tabi], *s1p)[1]= 0;
              // 添加第二个终结符,以防万一有人会尝试
          // 将这个单一字符串作为字符串对来读取;
            if(++str__tabi>=str__tabM) str__tabi= 0;
            if(str__tabn<str__tabM) str__tabn++;
            }  // 单个字符串对于字符串表来说足够短
          }  // single string
        else {  // 字符串对
          *s2p= p;
          len2= strlen(p);
          p+= len2+1;
          if(!donotstore && len1+len2<=str__tabstrM) {
              // 字符串对 对于字符串表来说足够短
            memcpy(str__tab[str__tabi],*s1p,len1+len2+2);
            if(++str__tabi>=str__tabM) str__tabi= 0;
            if(str__tabn<str__tabM) str__tabn++;
            }  // 字符串对 对于字符串表来说足够短
          }  // 字符串对
        *pp= (byte*)p;
        }  // 直接给出的字符串(对)
      else {  // 通过引用给出的字符串(对)
        ref= pbf_uint32(pp);
        if(ref>str__tabn) {  // 无效的字符串引用(因为ref > 字符串表中有效字符串的数量)
          fprintf(stderr,"Invalid .o5m string reference: %i->%i\n",
            str__tabn,ref);
          *s1p= "(invalid)";
          if(s2p!=NULL)  // 调用者需要一个字符串对
            *s2p= "(invalid)";
          }  // 无效的字符串引用
        else {  // 有效的字符串引用
          ref= str__tabi-ref; // 向前找引用的索引
          if(ref<0) ref+= str__tabM;
          *s1p= str__tab[ref];
          if(s2p!=NULL)  // 调用者需要一个字符串对
            *s2p= strchr(str__tab[ref],0)+1; 
        // (strchr: 从字符串 str__tab[ref] 中寻找字符0第一次出现的位置),然后+1,即定位到了下一个字符串
          }  // 有效的字符串引用
        }  // 通过引用给出的字符串(对)
      }  // str_read()
    
    //------------------------------------------------------------
    // end   Module str_   字符串读取模块
    //------------------------------------------------------------
    
    static inline char* sint32tosfix7(int32_t v,char* sp) {
      // 将sint32作为7位小数定点值并将其转换为字符串;
      // v: 整数值(定点);
      // sp[13]: 目标字符串;
      // 返回: sp;
      char* s1,*s2,c;
      int i;
    
      s1= sp;
      if(v<0) // 负数
        { *s1++= '-'; v= -v; }
      s2= s1;
      i= 7;
      while((v%10)==0 && i>0)  // trailing zeroes
        { v/= 10;  i--; }
      while(--i>=0)
        { *s2++= (v%10)+'0'; v/= 10; }
      *s2++= '.';
      do
        { *s2++= (v%10)+'0'; v/= 10; }
        while(v>0);
      *s2--= 0;
      while(s2>s1)
        { c= *s1; *s1= *s2; *s2= c; s1++; s2--; }
      return sp;
      }  // sint32tosfix7()
    
    static inline void uint64totimestamp(uint64_t v,char* sp) {
      // 将sint64转换为OSM格式的时间戳,
      // 举例说: "2010-09-30T19:23:30Z";
      // v: 时间戳值;
      // sp[21]: 目标字符串;
      time_t vtime;
      struct tm tm;
      int i;
    
      vtime= v;
      #if __WIN32__
      memcpy(&tm,gmtime(&vtime),sizeof(tm));
      #else
      gmtime_r(&vtime,&tm);
      #endif
      i= tm.tm_year+1900;
      sp+= 3; *sp--= i%10+'0';
      i/=10; *sp--= i%10+'0';
      i/=10; *sp--= i%10+'0';
      i/=10; *sp= i%10+'0';
      sp+= 4; *sp++= '-';
      i= tm.tm_mon+1;
      *sp++= i/10+'0'; *sp++= i%10+'0'; *sp++= '-';
      i= tm.tm_mday;
      *sp++= i/10+'0'; *sp++= i%10+'0'; *sp++= 'T';
      i= tm.tm_hour;
      *sp++= i/10+'0'; *sp++= i%10+'0'; *sp++= ':';
      i= tm.tm_min;
      *sp++= i/10+'0'; *sp++= i%10+'0'; *sp++= ':';
      i= tm.tm_sec%60;
      *sp++= i/10+'0'; *sp++= i%10+'0'; *sp++= 'Z'; *sp= 0;
      }  // uint64totimestamp()
    
    //------------------------------------------------------------
    
    static int process_o5m(const char* filename) {
      // 开始处理o5m对象;
      // 返回: ==0: ok; !=0: 错误;
      bool write_testmode;  // 如果为真: 报告未知的 o5m ids
      int otype;  // 当前处理对象的类型;
        // 0: node; 1: way; 2: relation;
      int64_t o5id;  // for o5m delta coding
      int32_t o5lon,o5lat;  // for o5m delta coding
      int64_t o5histime;  // for o5m delta coding
      int64_t o5hiscset;  // for o5m delta coding
      int64_t o5ref[4];  // for o5m delta coding for nodes, ways, relations,
        // and dummy object (just to allow index division by 4)
      bool o5endoffile;  // 文件的逻辑结束(数据集id 0xfe)
      byte* bufp;  // 在读取缓冲区的指针
      byte* bufe;  // 在读取缓冲区的指针, 对象的结束
      byte b;  // 已读取的最新字节
      int l;
    
      // 程序初始化
      write_testmode= false;  // do not criticize unknown o5m ids
      o5endoffile= false;
    
      // 读 .o5m 文件头
      read_open(filename);
      read_input();
      bufp= read_bufp;
      if(read_bufp>=read_bufe) {  // 文件为空
        fprintf(stderr,"Please supply .o5m file at stdin.\n");
    return 2;
        }
      if(bufp[0]!=0xff || bufp[1]!=0xe0 || (
          strzcmp((char*)bufp+2,"\x04""o5m2")!=0 &&
          strzcmp((char*)bufp+2,"\x04""o5c2")!=0 )) {
          // not an .o5m format
          fprintf(stderr,"Unknown input file format.\n");
    return 3;
        }
      bufp+= 7;  // 跳过.o5m文件头
    
      // 处理文件
      for(;;) {  //读取输入文件中的所有对象
    
        // 获取下一个对象
        read_input();
        if(read_bufp>=read_bufe)  // 物理文件结束
      break;
        if(o5endoffile) {  // 在文件的逻辑结束之后
          fprintf(stderr,"Warning: unexpected contents "
            "after logical end of file.\n");
      break;
          }
        bufp= read_bufp;
        b= *bufp;
    
        // 关心文件头对象和特殊对象
        if(b<0x10 || b>0x12) {  // 不是常规的OSM对象
          if(b>=0xf0) {  // 单字节数据集
            if(b==0xff) {  // 文件开始, resp. o5m 重置
              // 为写入o5m文件重置计数器;
              o5id= 0;
              o5lat= o5lon= 0;
              o5hiscset= 0;
              o5histime= 0;
              o5ref[0]= o5ref[1]= o5ref[2]= 0;
              str_reset();
              }
            else if(b==0xfe) // 文件结束
              o5endoffile= true;
            else if(write_testmode)
              fprintf(stderr,"Unknown .o5m short dataset id: 0x%02x\n",b);
            read_bufp++;
            }  // 单字节数据集
          else {  // 多字节数据集
            bufp++;
            l= pbf_uint32(&bufp);
            bufe= bufp+l;
            if(b==0xdc) {
                // 文件的时间戳
              if(bufp<bufe) {
                char ts[25];
    
                uint64totimestamp(pbf_sint64(&bufp),ts);
                printf("file timestamp: %s\n",ts);
                }
              }  // 文件的时间戳
            else if(b==0xdb) {  // border box
              char s[15];
    
              if(bufp<bufe) printf("bBox x1=%s\n",
                sint32tosfix7(pbf_sint32(&bufp),s));
              if(bufp<bufe) printf("bBox y1=%s\n",
                sint32tosfix7(pbf_sint32(&bufp),s));
              if(bufp<bufe) printf("bBox x2=%s\n",
                sint32tosfix7(pbf_sint32(&bufp),s));
              if(bufp<bufe) printf("bBox y2=%s\n",
                sint32tosfix7(pbf_sint32(&bufp),s));
              }  // border box
            else {  // 未知的多字节数据集
              if(write_testmode)
                fprintf(stderr,"Unknown .o5m dataset id: 0x%02x\n",b);
              }  // 未知的多字节数据集
            read_bufp= bufe;
            }  // 多字节数据集
      continue;
          }  // 不是常规的OSM对象
        // 这里: 常规OSM对象
        otype= b&3;
        bufp++;  // 跳过数据集id
    
        // 读一个osm对象
    
        // 读取对象id
        l= pbf_uint32(&bufp);
        read_bufp= bufe= bufp+l;
        printf("%s: %"PRIi64"\n",ONAME(otype),o5id+= pbf_sint64(&bufp));
        /* 读作者 */ {
          uint32_t hisver; // 版本号
          int64_t histime; // 时间戳
    
          hisver= pbf_uint32(&bufp);
          if(hisver!=0) {  // 作者信息有效
            printf("    version: %"PRIi32"\n",hisver);
            histime= o5histime+= pbf_sint64(&bufp);
            if(histime!=0) {
              char ts[25];
              char* hisuid;
              char* hisuser;
    
              uint64totimestamp(histime,ts);
              printf("    timestamp: %s\n",ts);
              printf("    changeset: %"PRIi64"\n",
                o5hiscset+= pbf_sint64(&bufp)); // 变更集
              str_read(&bufp,&hisuid,&hisuser); // 取出uid和user,并构建字符串表
              printf("    uid/user: %"PRIu32" %s\n",
                (uint32_t)pbf_uint64((byte**)&hisuid),hisuser); // 作者ID与姓名
              }
            }  // 作者信息有效
          }  // 读作者
        if(bufp>=bufe)
            // 只有id和作者,即这是一个删除请求
          printf("  action: delete\n");
        else {  // not a delete request
          // 读取坐标(仅用于节点)
          if(otype==0) {  // node
            char s[15];
    
            printf("  lon: %s\n",
              sint32tosfix7(o5lon+= pbf_sint32(&bufp),s));
            printf("  lat: %s\n",
              sint32tosfix7(o5lat+= pbf_sint32(&bufp),s));
            }  // node
          // 读取noderefs(仅用于路线)
          if(otype==1) {  // way
            byte* bp;
    
            l= pbf_uint32(&bufp); // noderefs 的长度
            bp= bufp+l; // 跳到 noderefs 的结尾
            if(bp>bufe) bp= bufe;  // (format error)
            while(bufp<bp) // 没到结尾,正常解析
              printf("  noderef: %"PRIi64"\n",
                o5ref[0]+= pbf_sint64(&bufp));
            }  // way
          // 读取参考(仅用于关系)
          else if(otype==2) {  // relation
            byte* bp;
            int64_t ri;  // 暂时的,refid 参考的id
            int rt;  // 暂时的, reftype 参考的类型
            char* rr;  // 暂时的, refrole 参考的角色
    
            l= pbf_uint32(&bufp); // reference 的长度
            bp= bufp+l;  // 跳到 reference 的结尾
            if(bp>bufe) bp= bufe;  // (format error)
            while(bufp<bp) { // 没到结尾,正常解析
              ri= pbf_sint64(&bufp);
              str_read(&bufp,&rr,NULL);
              rt= *rr++ & 3;  // convert '0'..'2' to 0..2
              printf("  ref: %s %"PRIi64" %s\n",
                ONAME(rt),o5ref[rt]+= ri,rr);
              }
            }  // relation
          // 读取对象的 key/val 对
          while(bufp<bufe) {
            char* kp,*vp;
    
            str_read(&bufp,&kp,&vp);
            printf("  key/val: %s=%s\n",kp,vp);
            }
          }  // not a delete request
    
        }  // 读取输入文件中的所有对象
      if(!o5endoffile)  // 缺少文件的逻辑结束
        fprintf(stderr,"Unexpected end of input file.\n");
      return 0;
      }  // process_o5m()
    
    int main(int argc,char** argv) {
      // main procedure;
      int r;
    
      #if __WIN32__
        setmode(fileno(stdout),O_BINARY);
        setmode(fileno(stdin),O_BINARY);
      #endif
    
      r= process_o5m(argv[1]);
      return r;
      }  // main()
    
    

    相关文章

      网友评论

          本文标题:o5mparser

          本文链接:https://www.haomeiwen.com/subject/povczxtx.html