dbRoot.v5是GE的主要的配置文件,其中包括层列表,提供程序列表(图层和快照的内容提供程序),图层的显示样式,可能的服务器列表(天空,火星等),当前数据库版本和当前密钥,用于解密所有传输的数据。
目前,这个文件可以以两种格式传输(有条件:第一版和第二版),二进制结构不同,但最后携带相同的数据:
- 适用于5.1及以下客户(较小版本的客户) - 第一版
- 对于5.2及更早版本的客户(旧版客户端) - 第二版
此外,客户端5.2.1.1329(来自标尺5.2的第一个客户端)以及稍后支持该文件的两个版本(第二个版本是默认版本,第一个版本仅在第二个版本文件不可用时加载)。
首先从服务器请求此文件。如果无法从Internet下载此文件,则客户端会尝试从缓存中下载该文件(第一版文件存储在dbCache.dat中,第二版存储在dbroot_cache中)。在这种情况下,如果客户端无法从缓存中下载它(例如,缓存为空),则客户端的工作将被中断,并且将报告无法连接到服务器。
每次客户端启动时都会下载此文件(对于Sky,Mars和History服务器 - 每次会话一次,切换到此模式时)。
请求格式
客户端生成此文件请求的方式取决于Windows语言设置,GoogleEarth自己的设置,以及客户端的旧版本以及客户端的版本和类型。地球视图模式的典型查询示例:
请求第一版文件:
http://kh.google.com/dbRoot.v5?hl=ru-RU&gl=ru
第二版的文件请求:
http://kh.google.com/dbRoot.v5?hl=ru-RU&gl=ru&output=proto&cv=5.2.1.1329&ct=free
其中,hl = ru-RU是用户的语言
gl = ru - 用户的位置
output = proto - 容器格式
cv = 5.2.1.1329 - 客户端版本
ct =免费 - 客户类型(免费/专业版)
关键
解密数据的密钥从第9个字节开始,长度为1016个字节。为了在解密算法中使用,必须补充8个零(在前面)到1024个字
原文地址:https://greverse.bitbucket.io/dbroot.htm
相关代码:python 代码地址
import os, sys, requests, struct, zlib
# urls:
# kh.google.com/dbRoot.v5 < 秘钥和地图版本信息
# kh.google.com/flatfile?q2-0-q.705 < QTree数据
# kh.google.com/flatfile?f1-030-i.704 < 瓦片图像
# /dbRoot.v5?hl=zh-hans-cn&gl=cn&output=proto&cv=5.2.1.1588&ct=free
# 1.
def Eval(fname, key):
# 解码数据
if (os.path.exists(fname)==False): return None
if (os.path.getsize(fname)==0): return None
f = open(fname, 'rb+')
data = f.read() # 读取文件内容
f.close()
#outdata = [0 for i in range(len(data))] # 创建一个结果数组
outdata = bytearray(len(data)) # 创建一个结果数组
index = 16
for i in range(0, len(data)):
outdata[i] = ord(data[i]) ^ ord(key[index+8])
index += 1
if (index % 8 == 0): index += 16
if (index >= 1016): index = (index + 8) % 24
return outdata
def EvalData(data, key):
# 解码数据
outdata = bytearray(len(data)) # 创建一个结果数组
index = 16
for i in range(0, len(data)):
outdata[i] = ord(data[i]) ^ ord(key[index+8])
index += 1
if (index % 8 == 0): index += 16
if (index >= 1016): index = (index + 8) % 24
return outdata
def ReadKEY(fname):
# 读取KEY文件
f = open(fname, 'rb+')
data = f.read()
f.close()
return data
def ReadVersion(fname):
# 读取dbRoot.v5文件里的版本号
if (os.path.exists(fname)==False): return None
if (os.path.getsize(fname)==0): return None
f = open(fname, 'rb+')
f.seek(6)
value = f.read(2)
f.close()
version = struct.unpack('h', value)[0]
version = version ^ 0x4200
return version
def ReadDBRoot():
# 读取dbRoot.v5文件
# 详细说明 http://greverse.bitbucket.org/dbroot.htm
# 00-03: 固定 9464874E
# 04-05: 数据版本 6600
# 06-07: 地图版本 比如 C240 需要与 0x4200 进行异或运算得出最终版本
# 08-1023: 数据秘钥共1016字节
# 1024-: 加密的XML数据
pass
def Tile2QuadKEY(tileX, tileY, zoom):
# 瓦片坐标转四叉树
result = '0'
for i in range(zoom, 0, -1):
digit = 0
mask = 1 << (i - 1)
if ((tileX & mask) != 0): digit += 1
if ((tileY & mask) != 0): digit += 2
# 由于谷歌四叉树算法和必应四叉树算法不一致
# 所以取巧采用对照表的方法可以解决 但第一位始终是0
# 对照表
# 必应 -> 谷歌
# 0 -> 3
# 1 -> 2
# 2 -> 0
# 3 -> 1
if (digit == 0): result += '3'
elif (digit == 1): result += '2'
elif (digit == 2): result += '0'
elif (digit == 3): result += '1'
return result
def QuadKEY2Tile(nums):
# 四叉树转 反转的时候也必须通过对照表
tileX = 0
tileY = 0
nums = nums[1:] # 第一位是0所以取掉
zoom = len(nums)
for i in range(zoom, 0, -1):
mask = 1 << (i - 1)
if (nums[zoom - i] == '3'):
continue
elif (nums[zoom - i] == '2'):
tileX |= mask
continue
elif (nums[zoom - i] == '0'):
tileY |= mask
continue
elif (nums[zoom - i] == '1'):
tileX |= mask
tileY |= mask
continue
return tileX, tileY, zoom
def Hex2Time(data):
# 十六进制转时间
# data: 传入16进制数据
month = int(data & 0xF) # 月
day = int((data & 0x1F0)>>4) # 日
year = int((data & 0xFFE00)>>9) # 年
return year, month, day
def Time2Hex(year, month, day):
# 时间转十六进制
pass
if __name__ == '__main__':
print '[==DoDo==]'
print 'GE Tiles.'
print 'Encode: %s' % sys.getdefaultencoding()
# 解密瓦片数据
#keydata = ReadKEY('data/key.bin')
#imgdata = Eval('data/_flatfile-f1c-0201202-t.705', keydata)
#f = open('out.jpg', 'wb')
#f.write(imgdata)
#f.flush()
#f.close()
# 时间字符串转时间
#Hex2Time(int('0xfa99b', 16))
# 瓦片坐标和四叉树互转
#print Tile2QuadKEY(3, 5, 3)
#print 'X:%s Y:%s Z:%s' % QuadKEY2Tile('0201202')
# 读取地图版本
#print ReadVersion('data/dbRoot.v5')
# 解码QTree数据
keydata = ReadKEY('data/key.bin')
zlibdata = Eval('data/_flatfile-q2-0-q.706', keydata)
f = open('data.z', 'wb') # 解密后的压缩数据
f.write(zlibdata)
f.flush()
f.close()
unzlibdata = zlib.decompress(str(zlibdata[8:]))
f = open('data.u', 'wb') # 解压后的真实数据
f.write(unzlibdata)
f.flush()
f.close()
'''
# 下载L2级别影像进行测试
keydata = ReadKEY('data/key.bin')
for x in range(0, 4):
for y in range(0, 4):
nums = Tile2QuadKEY(x, y, 2)
url = 'http://kh.google.com/flatfile?f1-{0}-i.705'.format(nums)
response = requests.get(url, stream=True)
data = response.raw.read()
savefile = 'out/_{0}.dat'.format(nums)
f = open(savefile, 'wb')
f.write(data)
f.flush()
f.close()
savefile = 'out/{0}.jpg'.format(nums)
data = EvalData(data, keydata)
f = open(savefile, 'wb')
f.write(data)
f.flush()
f.close()
'''
print 'OK.'