[ZIP] Replace ZipString class with fileprivate extensions to String and Data

This commit is contained in:
Timofey Solomko
2018-08-12 19:28:45 +03:00
parent b898b433f1
commit 3ed501cdfd
3 changed files with 81 additions and 90 deletions
-4
View File
@@ -36,7 +36,6 @@
062C1D7C1F8FCA9300917968 /* TarExtendedHeader.swift in Sources */ = {isa = PBXBuildFile; fileRef = 062C1D7B1F8FCA9300917968 /* TarExtendedHeader.swift */; };
0631CB061F81109E00A2E0AB /* Deflate+Constants.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0631CB051F81109E00A2E0AB /* Deflate+Constants.swift */; };
0634D9831F5207C30002B675 /* SuffixArray.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0634D9821F5207C30002B675 /* SuffixArray.swift */; };
06393DF51F1A7F8E00A647A0 /* ZipString.swift in Sources */ = {isa = PBXBuildFile; fileRef = 06393DF41F1A7F8E00A647A0 /* ZipString.swift */; };
063DF10D1DE1F07800F38082 /* Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 063DF1061DE1F07800F38082 /* Extensions.swift */; };
063DF1131DE1F07800F38082 /* DecodingHuffmanTree.swift in Sources */ = {isa = PBXBuildFile; fileRef = 063DF1081DE1F07800F38082 /* DecodingHuffmanTree.swift */; };
0642998B206017590044BA0C /* ZipExtraField.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0642998A206017590044BA0C /* ZipExtraField.swift */; };
@@ -248,7 +247,6 @@
0631CB051F81109E00A2E0AB /* Deflate+Constants.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Deflate+Constants.swift"; sourceTree = "<group>"; };
063364E21DC52979007E313F /* GzipArchive.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = GzipArchive.swift; sourceTree = "<group>"; };
0634D9821F5207C30002B675 /* SuffixArray.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SuffixArray.swift; sourceTree = "<group>"; };
06393DF41F1A7F8E00A647A0 /* ZipString.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ZipString.swift; sourceTree = "<group>"; };
063DF1061DE1F07800F38082 /* Extensions.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = Extensions.swift; path = Sources/Common/Extensions.swift; sourceTree = SOURCE_ROOT; };
063DF1081DE1F07800F38082 /* DecodingHuffmanTree.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = DecodingHuffmanTree.swift; path = Sources/Common/DecodingHuffmanTree.swift; sourceTree = SOURCE_ROOT; };
0642998A206017590044BA0C /* ZipExtraField.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ZipExtraField.swift; sourceTree = "<group>"; };
@@ -588,7 +586,6 @@
0642998A206017590044BA0C /* ZipExtraField.swift */,
0606CF8020641209002B6EE9 /* StandardExtraFields.swift */,
061C063C1F0E8AB700832F0C /* ZipError.swift */,
06393DF41F1A7F8E00A647A0 /* ZipString.swift */,
061C064C1F0E901C00832F0C /* ZipLocalHeader.swift */,
061C06471F0E8FF500832F0C /* ZipCentralDirectoryEntry.swift */,
061C06511F0E904600832F0C /* ZipEndOfCentralDirectory.swift */,
@@ -1110,7 +1107,6 @@
0620F4C81F8E24BF001C9B7A /* DecompressionAlgorithm.swift in Sources */,
0686A6451FA4C47300E89C9E /* FileSystemType+Zip.swift in Sources */,
06CDFCA31F111D6C00292758 /* BZip2Error.swift in Sources */,
06393DF51F1A7F8E00A647A0 /* ZipString.swift in Sources */,
06CFF6B22078C5A5003B8375 /* TarEntryInfoProvider.swift in Sources */,
06CC3FE21F8AAF3100BD576D /* ByteReader+XZ.swift in Sources */,
065D0ADC1F2B9D9100CE2DA8 /* 7zEntryInfo.swift in Sources */,
+81 -2
View File
@@ -20,12 +20,91 @@ extension ByteReader {
if useUtf8 {
return String(data: stringData, encoding: .utf8)
}
if ZipString.cp437Available && !ZipString.needsUtf8(stringData) {
if String.cp437Available && !stringData.needsUtf8() {
return String(data: stringData, encoding: String.Encoding(rawValue:
CFStringConvertEncodingToNSStringEncoding(ZipString.cp437Encoding)))
CFStringConvertEncodingToNSStringEncoding(String.cp437Encoding)))
} else {
return String(data: stringData, encoding: .utf8)
}
}
}
fileprivate extension String {
#if os(Linux)
static let cp437Encoding: CFStringEncoding = UInt32(truncatingIfNeeded: UInt(kCFStringEncodingDOSLatinUS))
static let cp437Available: Bool = CFStringIsEncodingAvailable(cp437Encoding)
#else
static let cp437Encoding = CFStringEncoding(CFStringEncodings.dosLatinUS.rawValue)
static let cp437Available = CFStringIsEncodingAvailable(cp437Encoding)
#endif
}
fileprivate extension Data {
func needsUtf8() -> Bool {
// UTF-8 can have BOM.
if self.count >= 3 {
if self[self.startIndex] == 0xEF && self[self.startIndex + 1] == 0xBB && self[self.startIndex + 2] == 0xBF {
return true
}
}
var index = self.startIndex
while index < self.endIndex {
let byte = self[index]
if byte <= 0x7F { // This simple byte can exist both in CP437 and UTF-8.
index += 1
continue
}
// Otherwise, it has to be correct code sequence in case of UTF-8.
// If code sequence is incorrect, then it is CP437.
let codeLength: Int
if byte >= 0xC2 && byte <= 0xDF {
codeLength = 2
} else if byte >= 0xE0 && byte <= 0xEF {
codeLength = 3
} else if byte >= 0xF0 && byte <= 0xF4 {
codeLength = 4
} else {
return false
}
if index + codeLength - 1 >= self.endIndex {
return false
}
for i in 1..<codeLength {
if self[index + i] & 0xC0 != 0x80 {
return false
}
}
if codeLength == 3 {
let ch = (UInt32(truncatingIfNeeded: self[index]) & 0x0F) << 12 +
(UInt32(truncatingIfNeeded: self[index + 1]) & 0x3F) << 6 +
UInt32(truncatingIfNeeded: self[index + 2]) & 0x3F
if ch < 0x0800 || ch >> 11 == 0x1B {
return false
}
} else if codeLength == 4 {
let ch = (UInt32(truncatingIfNeeded: self[index]) & 0x07) << 18 +
(UInt32(truncatingIfNeeded: self[index + 1]) & 0x3F) << 12 +
(UInt32(truncatingIfNeeded: self[index + 2]) & 0x3F) << 6 +
UInt32(truncatingIfNeeded: self[index + 3]) & 0x3F
if ch < 0x10000 || ch > 0x10FFFF {
return false
}
}
return true
}
// All bytes were in range 0...0x7F, which can be both in CP437 and UTF-8.
// We solve this ambiguity in favor of CP437.
return false
}
}
-84
View File
@@ -1,84 +0,0 @@
// Copyright (c) 2018 Timofey Solomko
// Licensed under MIT License
//
// See LICENSE for license information
import Foundation
#if os(Linux)
import CoreFoundation
#endif
class ZipString {
#if os(Linux)
static let cp437Encoding: CFStringEncoding = UInt32(truncatingIfNeeded: UInt(kCFStringEncodingDOSLatinUS))
static let cp437Available: Bool = CFStringIsEncodingAvailable(cp437Encoding)
#else
static let cp437Encoding = CFStringEncoding(CFStringEncodings.dosLatinUS.rawValue)
static let cp437Available = CFStringIsEncodingAvailable(cp437Encoding)
#endif
static func needsUtf8(_ data: Data) -> Bool {
// UTF-8 can have BOM.
if data.count >= 3 {
if data[data.startIndex] == 0xEF && data[data.startIndex + 1] == 0xBB && data[data.startIndex + 2] == 0xBF {
return true
}
}
var index = data.startIndex
while index < data.endIndex {
let byte = data[index]
if byte <= 0x7F { // This simple byte can exist both in CP437 and UTF-8.
index += 1
continue
}
// Otherwise, it has to be correct code sequence in case of UTF-8.
// If code sequence is incorrect, then it is CP437.
let codeLength: Int
if byte >= 0xC2 && byte <= 0xDF {
codeLength = 2
} else if byte >= 0xE0 && byte <= 0xEF {
codeLength = 3
} else if byte >= 0xF0 && byte <= 0xF4 {
codeLength = 4
} else {
return false
}
if index + codeLength - 1 >= data.endIndex {
return false
}
for i in 1..<codeLength {
if data[index + i] & 0xC0 != 0x80 {
return false
}
}
if codeLength == 3 {
let ch = (UInt32(truncatingIfNeeded: data[index]) & 0x0F) << 12 +
(UInt32(truncatingIfNeeded: data[index + 1]) & 0x3F) << 6 +
UInt32(truncatingIfNeeded: data[index + 2]) & 0x3F
if ch < 0x0800 || ch >> 11 == 0x1B {
return false
}
} else if codeLength == 4 {
let ch = (UInt32(truncatingIfNeeded: data[index]) & 0x07) << 18 +
(UInt32(truncatingIfNeeded: data[index + 1]) & 0x3F) << 12 +
(UInt32(truncatingIfNeeded: data[index + 2]) & 0x3F) << 6 +
UInt32(truncatingIfNeeded: data[index + 3]) & 0x3F
if ch < 0x10000 || ch > 0x10FFFF {
return false
}
}
return true
}
// All bytes were in range 0...0x7F, which can be both in CP437 and UTF-8.
// We solve this ambiguity in favor of CP437.
return false
}
}