简体   繁体   English

Swift Unzipping zip file and find xml file from base64 data from Gmail API

[英]Swift Unzipping zip file and find xml file from base64 data from Gmail API

This question is regarding a DMARC report viewer app in iOS 13 using SwiftUI and Gmail API.这个问题是关于 iOS 13 中的 DMARC 报告查看器应用程序,使用 SwiftUI 和 Gmail ZDB974238714CA81DE63ZA7ACE14 The reports are mailed to our admin email id by google in xml format which will be zipped.报告通过谷歌以 xml 格式邮寄给我们的管理员 email id,该格式将被压缩。 So basically it is a zip attachment.所以基本上它是一个 zip 附件。 So here, GMail API is used to access those specific mail using filter and got all the base64 encoded data from API.所以在这里,GMail API 用于使用过滤器访问那些特定的邮件,并从 ZDB16344238D018CA8 获取所有 base64 编码数据。 Also decoded it to Data type data.还将其解码为数据类型数据。 That far is OK.这么远还可以。 Next part is where data of zip file in byte format is decompressed and extract xml file inside in String type.下一部分是zip文件的字节格式数据被解压并以String类型提取xml文件里面。 Then I need to parse XML.然后我需要解析XML。 I think I can figure out parsing with XMLParser.我想我可以用 XMLParser 进行解析。

Question: how to decompress zip file in Data type and get xml file from it as String type?问题:如何将zip文件解压为Data类型并从中获取xml文件为String类型?

INPUT: String in Base64 format from GMail API fetch (A zip file attachment with only 1 xml file inside)
OUTPUT: String in XML format
PLATFORM: iOS 13/Swift 5.2/SwiftUI/Xcode 11.4
ACTION: 

(INPUT)
base64: String | Decode -> Data
attachment.zip: Data | Decompress -> [Data]
ListOfFiles: [Data] | FirstIndex -> Data
dmarc.xml: Data | ContentOfXML -> String
(OUTPUT)

Update: I have tried an external package called Zip and it also failed.更新:我尝试了一个名为Zip的外部 package ,但它也失败了。

let path = try! FileManager.default.url(for: .documentDirectory, in: .userDomainMask, appropriateFor: nil, create: true)
let url = path.appendingPathComponent(messageId+".zip")
do {
    try data.write(to: url)
} catch {
    print("Error while writing: "+error.localizedDescription)
}
do {
    let unzipDirectory = try Zip.quickUnzipFile(url)
    print(unzipDirectory)
} catch let error as NSError {
    print("Error while unzipping: "+error.localizedDescription)
}

This code resulted in following error此代码导致以下错误

Error while unzipping: The operation couldn’t be completed. (Zip.ZipError error 1.)

Finally I found it.最后我找到了。 As it is mentioned in Ref 1 ,The email bodies are encoded in 7-bit US-ASCII data.正如参考文献 1中所述,email 主体以 7 位 US-ASCII 数据编码。 So this is why the base64 decoding did not work.所以这就是为什么 base64 解码不起作用的原因。

As defined in the rfc1341 :rfc1341中所定义:

An encoding type of 7BIT requires that the body is already in a seven-bit mail- ready representation. 7BIT 的编码类型要求正文已经是 7 位邮件就绪表示。 This is the default value -- that is, "Content-Transfer-Encoding: 7BIT" is assumed if the Content-Transfer-Encoding header field is not present.这是默认值——也就是说,如果 Content-Transfer-Encoding header 字段不存在,则假定为“Content-Transfer-Encoding: 7BIT”。

The whole code worked after adding the following.添加以下内容后,整个代码有效。

let edata: String = result.data.replacingOccurrences(of: "-", with: "+").replacingOccurrences(of: "_", with: "/")

As it is mentioned in Ref 2 , it just need character replacement on '-' with '+' and '_' with '/' inside base64 data received from gmail api.正如参考文献 2中所提到的,它只需要在从 gmail Z8A5DA52ED126447D359E70C08A8A 接收到的 base64 数据中的 '-' 上的字符替换为 '+' 和 '_' 与 '/'

func getAttachedData(messageId: String, attachmentId: String) {
    decode(self.urlBase+messageId+"/attachments/"+attachmentId+"?"+self.urlKey) { (result: Attachment) in
        let edata: String = result.data.replacingOccurrences(of: "-", with: "+").replacingOccurrences(of: "_", with: "/")
        if let data = Data(base64Encoded: edata, options: .ignoreUnknownCharacters) {
            let filemanager = FileManager.default
            let path = try! filemanager.url(for: .documentDirectory, in: .userDomainMask, appropriateFor: nil, create: true)
            let url = path.appendingPathComponent(messageId+".zip")
            do {
                try data.write(to: url)
            } catch {
                print("Error while writing: "+error.localizedDescription)
            }
            do {
                let unzipDirectory = try Zip.quickUnzipFile(url)
                print("Unzipped")
                do {
                    let filelist = try filemanager.contentsOfDirectory(at: unzipDirectory, includingPropertiesForKeys: [], options: [])

                    for filename in filelist {
                        print(filename.lastPathComponent)
                        print(filename.relativeString)
                        do {
                            let text = try String(contentsOf: filename, encoding: .utf8)
                            print(text)
                            DispatchQueue.main.async {
                                self.attachments.append(text)
                            }
                        } catch let error as NSError {
                            print("Error: \(error.localizedDescription)")
                        }
                    }
                } catch let error {
                    print("Error: \(error.localizedDescription)")
                }
            } catch let error as NSError {
                print("Error while unzipping: "+error.localizedDescription)
            }
        }
    }
}

Ref 1: https://stackoverflow.com/a/58590759/2382813参考 1: https://stackoverflow.com/a/58590759/2382813

Ref 2: https://stackoverflow.com/a/24986452/2382813参考 2: https://stackoverflow.com/a/24986452/2382813

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM