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;
}