选择性下载和提取数据 (CAB)

Posted

技术标签:

【中文标题】选择性下载和提取数据 (CAB)【英文标题】:Selective download and extraction of data (CAB) 【发布时间】:2018-09-06 16:10:25 【问题描述】:

所以我特别需要下载和提取 cab 文件,但每个 cab 文件的大小都很大 > 200MB。我想有选择地从驾驶室下载文件,因为其余数据无用。

到目前为止做了这么多:

    向服务器请求 1% 的文件。获取标头并解析它们。 根据This CAB Link获取文件列表及其偏移量。 向服务器发送 GET 请求,并将 Range 标头设置为文件 Offset 和 Offset+Size。 我能够得到响应,但它是“不可读”的,因为它被压缩了(LZX:21 - Acc to 7Zip) 无法使用 zlib 解压缩。抛出无效的标头。

我也不太明白,也无法追踪示例中显示的 CFFOLDERCFDATA 导致其未压缩。

totalByteArray =b''
eofiles =0
def GetCabMetaData(stream):
    global eofiles
    cabMetaData=
    try:
        cabMetaData["CabFormat"] = stream[0:4].decode('ANSI')
        cabMetaData["CabSize"] = struct.unpack("<L",stream[8:12])[0]
        cabMetaData["FilesOffset"] = struct.unpack("<L",stream[16:20])[0]
        cabMetaData["NoOfFolders"] = struct.unpack("<H",stream[26:28])[0]
        cabMetaData["NoOfFiles"] = struct.unpack("<H",stream[28:30])[0]
        # skip 30,32,34,35
        cabMetaData["Files"]= 
        cabMetaData["Folders"]= 
        baseOffset = cabMetaData["FilesOffset"]
        internalOffset = 0
        for i in range(0,cabMetaData["NoOfFiles"]):
            fileDetails = 
            fileDetails["Size"] =  struct.unpack("<L",stream[baseOffset+internalOffset:][:4])[0]
            fileDetails["UnpackedStartOffset"] = struct.unpack("<L",stream[baseOffset+internalOffset+4:][:4])[0]
            fileDetails["FolderIndex"] = struct.unpack("<H",stream[baseOffset+internalOffset+8:][:2])[0]
            fileDetails["Date"] = struct.unpack("<H",stream[baseOffset+internalOffset+10:][:2])[0]
            fileDetails["Time"] = struct.unpack("<H",stream[baseOffset+internalOffset+12:][:2])[0]
            fileDetails["Attrib"] = struct.unpack("<H",stream[baseOffset+internalOffset+14:][:2])[0]
            fileName =''
            for j in range(0,len(stream)):
                if(chr(stream[baseOffset+internalOffset+16 +j])!='\x00'):
                    fileName +=chr(stream[baseOffset+internalOffset+16 +j])
                else:
                    break
            internalOffset += 16+j+1
            cabMetaData["Files"][fileName] = (fileDetails.copy())
        eofiles = baseOffset + internalOffset

    except Exception as e:
        print(e)
        pass
    print(cabMetaData["CabSize"])
    return cabMetaData

def GetFileSize(url):
    resp = requests.head(url)
    return int(resp.headers["Content-Length"])

def GetCABHeader(url):
    global totalByteArray
    size = GetFileSize(url)
    newSize ="bytes=0-"+ str(int(0.01*size))
    totalByteArray = b''
    cabHeader= requests.get(url,headers="Range":newSize,stream=True)
    for chunk in cabHeader.iter_content(chunk_size=1024):
        totalByteArray += chunk


def DownloadInfFile(baseUrl,InfFileData,InfFileName):

    global totalByteArray,eofiles
    if(not os.path.exists("infs")):
        os.mkdir("infs")
    baseCabName = baseUrl[baseUrl.rfind("/"):]
    baseCabName = baseCabName.replace(".","_")
    if(not os.path.exists("infs\\" + baseCabName)):
        os.mkdir("infs\\"+baseCabName)
    fileBytes = b''
    newRange = "bytes=" + str(eofiles+InfFileData["UnpackedStartOffset"] ) + "-" + str(eofiles+InfFileData["UnpackedStartOffset"]+InfFileData["Size"] )
    data = requests.get(baseUrl,headers="Range":newRange,stream=True)
    with open("infs\\"+baseCabName +"\\" + InfFileName  ,"wb") as f:
        for chunk in data.iter_content(chunk_size=1024):
            fileBytes +=chunk
        f.write(fileBytes)
        f.flush()


    print("Saved File " + InfFileName)
    pass


def main(url):
    GetCABHeader(url)
    cabMetaData = GetCabMetaData(totalByteArray)
    for fileName,data in cabMetaData["Files"].items():
        if(fileName.endswith(".txt")):
            DownloadInfFile(url,data,fileName)

main("http://path-to-some-cabinet.cab")

所有文件详细信息均正确无误。我已经验证过了。

任何指导将不胜感激。我做错了吗?也许是另一种方式?

P.S : 已经看过This Post

【问题讨论】:

【参考方案1】:

首先,CAB 中的数据是原始 deflate,而不是 zlib 包装的 deflate。所以你需要让 zlib 的 inflate() 在初始化时使用负的 windowBits 值解码原始 deflate。

其次,CAB 格式并不完全使用标准 deflate,因为 32K 滑动窗口字典从一个块传送到下一个块。您需要使用 inflateSetDictionary() 在每个块的开头使用从最后一个块解压缩的最后 32K 设置字典。

【讨论】:

我会调查的。但是我到目前为止所做的是否正确?文件的 uOffsets 在文件夹内指定。还有对于第一个文件setDictionary 不需要设置吗?因为之前没有解压过? 我没有时间检查您的代码。是的,一开始没有字典。历史记录在文件夹开始时被清除。

以上是关于选择性下载和提取数据 (CAB)的主要内容,如果未能解决你的问题,请参考以下文章

win10英文语言包安装不了是怎么回事

[转]SQL SERVER2017|2019 安装程序无法与下载服务器联系。无法安装机器学习服务的问题解决方式

Win10语言包怎么安装,Win10中文语言包安装方法

如何给windows系统安装语言包

覆盖Android中文本选择(在WebView中)的默认上下文操作栏

如何在移动应用程序的cab文件中添加图标文件?