美文网首页
osmpbf-outline(C++版本的)

osmpbf-outline(C++版本的)

作者: 微雨旧时歌丶 | 来源:发表于2018-01-25 21:25 被阅读0次
    // osmpbf-outline(C++版本的),练习用
    
    #include <iostream>
    #include <fstream>
    #include <iomanip>
    
    // pbf blobs中使用到了zlib压缩
    #include <zlib.h> 
    
    // netinet中提供了network-byte-order的转换函数
    #include <netinet/in.h> 
    
    // 定义了几种扩展的整数类型和宏
    #include <stdint.h>  
    
    // 其它需要的头文件
    #include <string>
    #include <algorithm>
    #include <map>
    
    
    
    // 描述低级blob存储的头文件
    #include <osmpbf/fileformat.pb.h> 
    
    // 描述高级OSM对象的头文件
    #include <osmpbf/osmformat.pb.h> 
    
    // 以byte为单位的最大blob header的大小
    const int max_blob_header_size = 64 * 1024; // 64 kB
    
    // 以byte为单位的最大非压缩的blob的大小
    const int max_uncompressed_blob_size = 32 * 1024 * 1024; // 32 MB
    
    // 用于double和int之间的转换的经度/纬度分辨率
    const int lonlat_resolution = 1000 * 1000 * 1000; 
    
    
    
    // 格式化输出,info信息,warn警告,fatal错误(考虑改为err)
    // 用法:将用于向屏幕显示的std::cout替换为info()或其它
    // 例: info()<<"开始解析文件";  行尾自动换行
    
    // info 绿色
    struct info {
        info() {std::cout << "\033[32m";}
            template<typename T>info & operator<<(const T & t){ std::cout << t; return *this;}
        ~info() {std::cout << "\033[0m" << std::endl;}
    };
    
    // debug,白色,相当于std::cout<<... <<std::endl;
    
    struct debug {
        debug() {std::cout << "\033[0m";}
        template<typename T>debug & operator<<(const T & t){ std::cout << t; return *this;}
        ~debug() {std::cout << "\033[0m" << std::endl;}
    
    };
    
    //warn 黄色
    struct warn {
        warn() {std::cout << "\033[33m";}
        template<typename T>warn & operator<<(const T & t){ std::cout << t; return *this;}
        ~warn() {std::cout << "\033[0m" << std::endl;}
    };
    
    //fatal 红色
    struct fatal {
        fatal() {std::cout << "\033[31m";}
        template<typename T>fatal & operator<<(const T & t){ std::cout << t; return *this;}
        ~fatal() {std::cout << "\033[0m" << std::endl; exit(1);}
    };
    
    // 用于从文件中读取压缩的blob的buffer缓冲区
    char buffer[max_uncompressed_blob_size];
    
    // 用于进行解压缩blob的buffer缓冲区
    char unpack_buffer[max_uncompressed_blob_size];
    
    // pbf struct of a BlobHeader
    OSMPBF::BlobHeader blobheader;
    
    // pbf struct of a Blob
    OSMPBF::Blob blob;
    
    // pbf struct of an OSM HeaderBlock
    OSMPBF::HeaderBlock headerblock;
    
    // pbf struct of an OSM PrimitiveBlock
    OSMPBF::PrimitiveBlock primblock;
    
    // main函数
    int main(int argc, char** argv) {
        if (argc != 2) {
            std::cout << "Usage: " << argv[0] << " file_to_read.osm.pbf" << std::endl;
            return 1;
        }
    
        // 读入文件
            std::ifstream file;
        file.open(argv[1],std::ios::binary); 
        if (!file.is_open())
                 fatal() << "无法打开文件: " << argv[1];
            info() << "读取文件..." << argv[1];    //打开成功,开始解析数据的提示信息
    
        //////////////////////////////////////////////////////////////////
        //////////////////////////////////////////////////////////////////
    
        // 开始读取文件
        while (!file.eof()){
    
            int32_t sz; // 存储size,多次重复使用
    
            
    
            // 读取文件的前4bytes,这是blob-header的size
    
            if ( !file.read((char*)&sz, 4) ){
    
                info() << "读取文件完成!";
    
                break; //到达文件尾
    
            }
    
            // 将size从network byte-order转换为host hyte-order
    
            sz = ntohl(sz);
    
            // 确保blob-header < MAX_BLOB_HEADER_SIZE (64kB)
    
            if (sz > max_blob_header_size)
    
                fatal() << "blob-header-size is bigger then allowed " << sz 
    
                        << " > " << max_blob_header_size;
    
            // 从文件中读取blob-header到buffer中
    
            if (!file.read(buffer, sz))
    
                fatal() << "无法从文件中读取blob-header";
    
            // 从缓冲区中解析blob-header
    
            if (!blobheader.ParseFromArray(buffer, sz))
    
                // 解析结果存储在OSMPBF::BlobHeader结构对象中
    
                fatal() << "无法解析blob-header";
    
                // 输出blob-header的有关信息
    
            info() << "BlobHeader (" << sz <<"bytes)";
    
            debug() << "  type = " << blobheader.type();
    
            // 以下的blob的size
    
            sz = blobheader.datasize();
    
            debug() <<"  datasize = " << sz;
    
            // 可选的 indexdata
    
            if (blobheader.has_indexdata()) {
    
                debug() <<"  indexdata =  "<< blobheader.indexdata().size()<<"bytes";
    
            }       
    
            
    
            // 确保blob < MAX_BLOB_SIZE (64kB)
    
            if (sz > max_uncompressed_blob_size) 
    
                fatal()<<"blob-size is bigger then allowed";
    
            // 从文件中读取blob到buffer中
    
            if (!file.read(buffer, sz))
    
                fatal() << "无法从文件中读取blob";
    
            // 从缓冲区中解析blob
    
            if (!blob.ParseFromArray(buffer, sz))
    
                fatal() << "无法解析blob";
    
            
    
            // 输出blob-header的有关信息
    
            info() << "Blob  (" << sz <<"bytes)";
    
            // 有无数据流的标志,
    
            bool found_data = false;
    
            
    
            // 如果blob中有非压缩的数据
    
            if (blob.has_raw()) {
    
                // 则有至少一个数据流
    
                found_data = true;
    
                // blob-data的size
    
                sz = blob.raw().size();
    
                // 检查是否正确设置了raw_size
    
                if(sz != blob.raw_size())
    
                    warn() << "  reports wrong raw_size: " << blob.raw_size() << " bytes";  
    
                // 输出blob的有关信息
    
                debug()<<"  contains uncompressed data: " <<sz<<" bytes";
    
                // 将非压缩的数据拷贝到unpack_buffer中去
    
                memcpy(unpack_buffer, buffer, sz);
    
            }
    
            
    
            // 如果blob中有zlib压缩的数据
    
            if(blob.has_zlib_data()) {
    
                // 发出警告,因为这存在了多个数据流,而一个blob中只能包含一个数据流
    
                if (found_data)
    
                    warn()<<"  包含了多个数据流";
    
                // 至少一个数据流
    
                found_data = true;
    
                // 压缩数据的size
    
                sz = blob.zlib_data().size();
    
                
    
                // 输出压缩数据的信息
    
                debug() <<"  contains zlib-compressed data: "<<sz<<" bytes";
    
                debug() <<"  uncompressed size: "<<blob.raw_size()<<" bytes";
    
                
    
                // zlib的信息
    
                z_stream z;
    
                // next byte to decompress
    
                z.next_in  = (unsigned char*) blob.zlib_data().c_str();
    
                // number of bytes to decompress
    
                z.avail_in = sz;
    
                // place of next decompressed byte
    
                z.next_out = (unsigned char*) unpack_buffer;
    
                // space for decompressed data
    
                z.avail_out= blob.raw_size();           
    
                // misc
    
                z.zalloc   = Z_NULL;
    
                z.zfree    = Z_NULL;
    
                z.opaque   = Z_NULL;    
    
                
    
                if(inflateInit(&z) != Z_OK) {
    
                    fatal() << "failed to init zlib stream";
    
                }
    
                if(inflate(&z, Z_FINISH) != Z_STREAM_END) {
    
                    fatal() << "failed to inflate zlib stream";
    
                }
    
                if(inflateEnd(&z) != Z_OK) {
    
                    fatal() << "failed to deinit zlib stream";
    
                }   
    
                // unpacked size
    
                sz = z.total_out;   
    
            }
    
    
    
            //  如果blob中有lzma压缩的数据
    
            if(blob.has_lzma_data()) {
    
                // 发出警告,因为这存在了多个数据流,而一个blob中只能包含一个数据流
    
                if (found_data)
    
                    warn()<<"  包含了多个数据流";
    
                // 至少一个数据流
    
                found_data = true;
    
                // 输出压缩数据的信息
    
                debug() <<"  contains lzma-compressed data: "<<blob.lzma_data().size()<<" bytes";
    
                debug() <<"  uncompressed size: "<<blob.raw_size()<<" bytes";
    
                // 发出警告,lzma压缩还没有得到支持
    
                fatal() << "  lzma-decompression is not supported";
    
            }
    
            // 检查是否包含了至少一个数据流
    
            if (!found_data) 
    
                fatal() << "  does not contain any known data stream";
    
            
    
            // 切换不同的blob类型
    
            if (blobheader.type() == "OSMHeader") {
    
                // 输出OSMHeader blob的信息
    
                info()<<"  OSMHeader";
    
                
    
                // 从blob中解析HeaderBlock
    
                if (!headerblock.ParseFromArray(unpack_buffer, sz))
    
                    fatal() <<"unable to parse header block";
    
                
    
                //如果有bbox,输出
    
                if (headerblock.has_bbox()) {
    
                    OSMPBF::HeaderBBox bbox = headerblock.bbox();
    
                    debug() << std::setiosflags(std::ios::fixed) << std::setprecision(7)
    
                            << "    bbox: "<<(double)bbox.left() / lonlat_resolution<<","
    
                            << (double)bbox.bottom() / lonlat_resolution<<","
    
                            << (double)bbox.right() / lonlat_resolution<<","
    
                            << (double)bbox.top() / lonlat_resolution;
    
                }
    
                
    
                // tell about the required features
    
                for (int i = 0, l = headerblock.required_features_size(); i < l; i++) {
    
                    debug() <<"    required_feature: "<< headerblock.required_features(i);
    
                }   
    
                // tell about the optional features
    
                for (int i = 0, l = headerblock.optional_features_size(); i < l; i++) {
    
                    debug() <<"    optional_feature: "<< headerblock.optional_features(i);
    
                }
    
                // tell about the writing program
    
                if (headerblock.has_writingprogram())
    
                    debug() <<"    writingprogram: "<< headerblock.writingprogram();
    
                //  tell about the source
    
                if (headerblock.has_source())
    
                    debug() <<"    source: "<< headerblock.source();    
    
            }
    
            else if (blobheader.type() == "OSMData") {
    
                // 输出OSMData blob的信息
    
                info()<<"  OSMData";
    
                
    
                // 从blob中解析PrimitiveBlock
    
                if (!primblock.ParseFromArray(unpack_buffer, sz))
    
                    fatal() <<"unable to parse primitive block";    
    
                // tell about the block's meta info
    
                debug() <<"    granularity: " << primblock.granularity();
    
                debug() <<"    lat_offset: " << primblock.lat_offset();
    
                debug() <<"    lon_offset: " << primblock.lon_offset();
    
                debug() <<"    date_granularity: " << primblock.date_granularity();
    
                
    
                // 输出关于stringtable
    
                debug() <<"    stringtable: " << primblock.stringtable().s_size()<<" items";
    
                // PrimitiveGroups的数量
    
                debug() <<"    primitivegroups: " << primblock.primitivegroup_size()<<" groups";
    
                
    
                // 遍历所有PrimitiveGroups
    
                for (int i = 0, l = primblock.primitivegroup_size(); i < l; i++) {
    
                    // Block中的一个PrimitiveGroup
    
                    OSMPBF::PrimitiveGroup pg = primblock.primitivegroup(i);
    
                    
    
                    bool found_items=false;
    
    
    
                    // 输出关于nodes
    
                    if (pg.nodes_size() > 0) {
    
                        found_items = true;
    
    
    
                        debug() <<"      nodes: " << pg.nodes_size();
    
                        if (pg.nodes(0).has_info()) {
    
                            debug()<<"        with meta-info";
    
                        }
    
                    }
    
    
    
                    // 输出关于dense nodes
    
                    if (pg.has_dense()) {
    
                        found_items = true;
    
    
    
                        debug() <<"      dense nodes: " << pg.dense().id_size();
    
                        if (pg.dense().has_denseinfo()) {
    
                            debug()<<"        with meta-info";
    
                        }
    
                    }
    
    
    
                    // 输出关于ways
    
                    if (pg.ways_size() > 0) {
    
                        found_items = true;
    
    
    
                        debug() << "      ways: " << pg.ways_size();
    
                        if (pg.ways(0).has_info()) {
    
                            debug() << "        with meta-info";
    
                        }
    
                    }
    
    
    
                    // 输出关于relations
    
                    if (pg.relations_size() > 0) {
    
                        found_items = true;
    
    
    
                        debug() << "      relations: " << pg.relations_size();
    
                        if (pg.relations(0).has_info()) {
    
                            debug() << "        with meta-info";
    
                        }
    
                    }
    
    
    
                    if (!found_items) {
    
                        warn()<<"      contains no items";
    
                    }
    
                }
    
            }
    
            else{
    
                // 未知的blob类型
    
                warn()<<"  unknown blob type: " << blobheader.type();
    
            }
    
        }
    
        // close the file pointer
    
        file.close();
    
    
    
        // clean up the protobuf lib
    
        google::protobuf::ShutdownProtobufLibrary();
    
        
    
        return 0;
    
    }
    

    相关文章

      网友评论

          本文标题:osmpbf-outline(C++版本的)

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