osmpbf-outline(C++版本的)

2018-01-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;

}
上一篇下一篇

猜你喜欢

热点阅读