diff --git a/IPSubnetcalc.swift b/IPSubnetcalc.swift index 160ee0c..09b5f08 100644 --- a/IPSubnetcalc.swift +++ b/IPSubnetcalc.swift @@ -85,6 +85,18 @@ class IPSubnetCalc: NSObject { //************* //IPv4 SECTION //************* + /** + Convert an IP address in its binary representation + + - Parameters: + - ipAddress: IP address in dotted decimal format like 192.168.1.42 + - space: add a space to each decimal + - dotted: add a dot to each decimal + + - Returns: + the binary representation of the given IP address + + */ static func binarize(ipAddress: String, space: Bool = false, dotted: Bool = true) -> String { var ipAddressBin = [String]() var binStr = String() @@ -117,10 +129,30 @@ class IPSubnetCalc: NSObject { return (binStr) } + /** + Convert the current IPv4 address to its binary representation + + - Parameter dotted: add dot to each decimal + + - Returns: + the binary representation of the current IP address + + */ func binaryMap(dotted: Bool = true) -> String { return (IPSubnetCalc.binarize(ipAddress: ipv4Address, space: false, dotted: dotted)) } + /** + Convert an IP address in its hexadecimal representation + + - Parameters: + - ipAddress: IP address in dotted decimal format like 192.168.1.42 + - dotted: add a dot to each decimal + + - Returns: + the hexadecimal representation of the given IP address + + */ static func hexarize(ipAddress: String, dotted: Bool = true) -> String { var ipDigits = [String]() var hexIP = String() @@ -142,11 +174,29 @@ class IPSubnetCalc: NSObject { return (hexIP) } + /** + Convert the current IPv4 address to its hexadecimal representation + + - Parameter dotted: add dot to each decimal + + - Returns: + the hexadecimal representation of the current IP address + + */ func hexaMap(dotted: Bool = true) -> String { return (IPSubnetCalc.hexarize(ipAddress: ipv4Address, dotted: dotted)) } - static func numerize(ipAddress: String) -> UInt32 { + /** + Convert an IP address in dotted decimal format to an UInt32 value + + - Parameter ipAddress: an IP address in dotted decimal format like 192.168.1.42 + + - Returns: + a digital IP address in UInt32 format + + */ + static func digitize(ipAddress: String) -> UInt32 { var ipAddressNum: UInt32 = 0 var ipDigits = [String]() @@ -170,12 +220,29 @@ class IPSubnetCalc: NSObject { } */ - //numerize a Mask bits value to UInt32 - static func numerize(maskbits: Int) -> UInt32 { + /** + Convert a mask value in bits to an UInt32 value + + - Parameter maskbits: subnet mask bits as in /XX notation + + - Returns: + a digital subnet mask in UInt32 format + + */ + static func digitize(maskbits: Int) -> UInt32 { return ((Constants.addr32Full << (32 - maskbits)) & Constants.addr32Full) } - static func digitize(ipAddress: UInt32) -> String { + /** + Convert an IP address in digital format to dotted decimal format + + - Parameter ipAddress: IP address in its digital format + + - Returns: + a String reprensenting the dotted decimal format of the given IP address + + */ + static func dottedDecimal(ipAddress: UInt32) -> String { var ipDigits = String() ipDigits.append(String(((ipAddress & Constants.addr32Digit1) >> Constants.classCbits)) + ".") @@ -185,6 +252,18 @@ class IPSubnetCalc: NSObject { return (ipDigits) } + /** + Check if the IP address is a valid IPv4 address + + - Parameters: + - ipAddress: IP address in dotted decimal format like 192.168.1.42 + - mask: Optionnal subnet mask + - classless: enable class less checks of the given IP address/mask + + - Returns: + Boolean if the given IP address is valid or not + + */ static func isValidIP(ipAddress: String, mask: String?, classless: Bool = false) -> Bool { var ip4Digits = [String]() @@ -231,38 +310,73 @@ class IPSubnetCalc: NSObject { return true } + /** + Returns current Subnet ID address + + - Returns: + the dotted decimal representation of the Subnet ID of the current IP address/mask + + */ func subnetId() -> String { var subnetId: UInt32 = 0 - let ipBits = IPSubnetCalc.numerize(ipAddress: self.ipv4Address) - let maskBits = IPSubnetCalc.numerize(maskbits: self.maskBits) + let ipBits = IPSubnetCalc.digitize(ipAddress: self.ipv4Address) + let maskBits = IPSubnetCalc.digitize(maskbits: self.maskBits) subnetId = ipBits & maskBits - return (IPSubnetCalc.digitize(ipAddress: subnetId)) + return (IPSubnetCalc.dottedDecimal(ipAddress: subnetId)) } + /** + Returns current broadcast address + + - Returns: + the dotted decimal representation of the broadcast address of the current IP address/mask + + */ func subnetBroadcast() -> String { var broadcast: UInt32 = 0 - let ipBits = IPSubnetCalc.numerize(ipAddress: self.ipv4Address) - let maskBits = IPSubnetCalc.numerize(maskbits: self.maskBits) + let ipBits = IPSubnetCalc.digitize(ipAddress: self.ipv4Address) + let maskBits = IPSubnetCalc.digitize(maskbits: self.maskBits) broadcast = ipBits & maskBits | (Constants.addr32Full >> self.maskBits) - return (IPSubnetCalc.digitize(ipAddress: broadcast)) + return (IPSubnetCalc.dottedDecimal(ipAddress: broadcast)) } + /** + Returns current Subnet Mask + + - Returns: + String of the current subnet mask as in /XX notation + + */ func subnetMask() -> String { var subnetMask: UInt32 = 0 subnetMask = Constants.addr32Full << (32 - self.maskBits) - return (IPSubnetCalc.digitize(ipAddress: subnetMask)) + return (IPSubnetCalc.dottedDecimal(ipAddress: subnetMask)) } + /** + Returns current Wildcard Subnet Mask + + - Returns: + the dotted decimal representation of the wildcard subnet mask of the current IP address/mask + + */ func wildcardMask() -> String { var wildcardMask: UInt32 = 0 wildcardMask = ~(Constants.addr32Full << (32 - self.maskBits)) - return (IPSubnetCalc.digitize(ipAddress: wildcardMask)) + return (IPSubnetCalc.dottedDecimal(ipAddress: wildcardMask)) } + /** + Returns the maximum hosts in the current subnet + + - Returns: + maximum hosts for the current mask + + */ func maxHosts() -> Int { var maxHosts: UInt32 = 0 @@ -273,6 +387,13 @@ class IPSubnetCalc: NSObject { return (Int(maxHosts)) } + /** + Returns the maximum CIDR subnets + + - Returns: + maximum CIDR subnets for the current mask + + */ func maxCIDRSubnets() -> Int { var max: Int = 0 @@ -281,6 +402,13 @@ class IPSubnetCalc: NSObject { return (max) } + /** + Returns the maximum CIDR Supernets + + - Returns: + maximum CIDR Supernets for the current mask + + */ func maxCIDRSupernet() -> Int { let classType = self.netClass() var result: Decimal @@ -306,36 +434,59 @@ class IPSubnetCalc: NSObject { return (1) } + /** + Returns the current subnet IP Range + + - Returns: + First IP address - Last IP address of the current IP address/mask + + */ func subnetRange() -> String { var range = String() var firstIP: UInt32 = 0 var lastIP: UInt32 = 0 if (maskBits == 31 || maskBits == 32) { - firstIP = IPSubnetCalc.numerize(ipAddress: subnetId()) - lastIP = IPSubnetCalc.numerize(ipAddress: subnetBroadcast()) + firstIP = IPSubnetCalc.digitize(ipAddress: subnetId()) + lastIP = IPSubnetCalc.digitize(ipAddress: subnetBroadcast()) } else { - firstIP = IPSubnetCalc.numerize(ipAddress: subnetId()) + 1 - lastIP = IPSubnetCalc.numerize(ipAddress: subnetBroadcast()) - 1 + firstIP = IPSubnetCalc.digitize(ipAddress: subnetId()) + 1 + lastIP = IPSubnetCalc.digitize(ipAddress: subnetBroadcast()) - 1 } - range = IPSubnetCalc.digitize(ipAddress: firstIP) + " - " + IPSubnetCalc.digitize(ipAddress: lastIP) + range = IPSubnetCalc.dottedDecimal(ipAddress: firstIP) + " - " + IPSubnetCalc.dottedDecimal(ipAddress: lastIP) return (range) } + /** + Returns the current CIDR subnet IP Range + + - Returns: + First IP address - Last IP address of the current CIDR IP address/mask + + */ func subnetCIDRRange() -> String { var range = String() var firstIP: UInt32 = 0 var lastIP: UInt32 = 0 - firstIP = IPSubnetCalc.numerize(ipAddress: subnetId()) - lastIP = IPSubnetCalc.numerize(ipAddress: subnetBroadcast()) - range = IPSubnetCalc.digitize(ipAddress: firstIP) + " - " + IPSubnetCalc.digitize(ipAddress: lastIP) + firstIP = IPSubnetCalc.digitize(ipAddress: subnetId()) + lastIP = IPSubnetCalc.digitize(ipAddress: subnetBroadcast()) + range = IPSubnetCalc.dottedDecimal(ipAddress: firstIP) + " - " + IPSubnetCalc.dottedDecimal(ipAddress: lastIP) return (range) } + /** + Returns the Network Class of an IP address + + - Parameter ipAddress: IPv4 address in dotted decimal format + + - Returns: + Network Class conforming to RFC 790 + + */ static func netClass(ipAddress: String) -> String { - let ipNum = IPSubnetCalc.numerize(ipAddress: ipAddress) + let ipNum = IPSubnetCalc.digitize(ipAddress: ipAddress) let addr1stByte = (ipNum & Constants.maskClassA) >> 24 if (addr1stByte < 127) { @@ -353,10 +504,24 @@ class IPSubnetCalc: NSObject { return ("E") } + /** + Returns the Network Class of the current IP address + + - Returns: + Network Class of the current IP address conforming to RFC 790 + + */ func netClass() -> String { return (IPSubnetCalc.netClass(ipAddress: ipv4Address)) } + /** + Returns the bits dedicated to the Subnet part of the IP Address + + - Returns: + bits dedicated to the Subnet part of the current IP Address + + */ func subnetBits() -> Int { let classType = self.netClass() var bits: Int = 0 @@ -379,6 +544,13 @@ class IPSubnetCalc: NSObject { return (bits) } + /** + Returns the bits dedicated to Network Class + + - Returns: + bits dedicated to the Network Class of the current IP address + + */ func classBits() -> Int { let classType = self.netClass() @@ -394,6 +566,13 @@ class IPSubnetCalc: NSObject { return (32) } + /** + Returns the mask bits for the Network Class + + - Returns: + mask bits dedicated for the Network Class of the current IP address + + */ func classMask() -> UInt32 { let classType = self.netClass() @@ -415,10 +594,19 @@ class IPSubnetCalc: NSObject { return (Constants.maskClassE) } + /** + Returns the number of bits of the mask + + - Parameter maskAddr: mask in dotted decimal format + + - Returns: + the number of bits for the given mask + + */ static func maskBits(maskAddr: String) -> Int { var bits: Int = 0 - var mask:UInt32 = IPSubnetCalc.numerize(ipAddress: maskAddr) + var mask:UInt32 = IPSubnetCalc.digitize(ipAddress: maskAddr) while (mask != 0) { bits += 1 mask <<= 1 @@ -427,6 +615,15 @@ class IPSubnetCalc: NSObject { return (bits) } + /** + Returns the number of bits of the mask + + - Parameter mask: mask in digitize format + + - Returns: + the number of bits for the given mask + + */ static func maskBits(mask: UInt32) -> Int { var bits: Int = 0 var tmpmask = mask @@ -439,6 +636,13 @@ class IPSubnetCalc: NSObject { return (bits) } + /** + Returns the number of bits dedicated to Network + + - Returns: + number of bits dedicated to the Network of the current IP address + + */ func netBits() -> Int { let classType = self.netClass() var bits: Int = 0 @@ -470,6 +674,13 @@ class IPSubnetCalc: NSObject { return (bits) } + /** + Returns the maximum number of subnets + + - Returns: + maximum number of subnets for the current Subnet bits + + */ func maxSubnets() -> Int { var maxSubnets: Int = 0 @@ -478,6 +689,15 @@ class IPSubnetCalc: NSObject { return (maxSubnets) } + /** + Returns the Bit Map representation + + - Parameter dotted: add dot at each decimal + + - Returns: + Bit Map reprensenation of the current ip address/mask + + */ func bitMap(dotted: Bool = true) -> String { let netBits = self.netBits() let subnetBits = self.subnetBits() @@ -502,7 +722,14 @@ class IPSubnetCalc: NSObject { return (bitMap) } - // return maskbits and number of max hosts for this mask + /** + Returns maskbits and number of max hosts for a requested number of hosts + + - Parameter hosts: number of requested hosts + + - Returns: maskbits and number of max hosts for the requested number of hosts + + */ static func fittingSubnet(hosts: UInt) -> (Int, UInt) { var maxHosts: UInt @@ -515,6 +742,9 @@ class IPSubnetCalc: NSObject { return (0, 0) } + /** + Display IP informations of the current IP address/mask + */ func displayIPInfo() { print("IP Host : " + self.ipv4Address) print("Mask bits : \(self.maskBits)") @@ -536,8 +766,8 @@ class IPSubnetCalc: NSObject { print("CIDR Network (Route) : " + self.subnetId()) print("CIDR Net Notation : " + self.subnetId() + "/" + String(self.maskBits)) print("CIDR Address Range : " + self.subnetCIDRRange()) - print("IP number in binary : " + String(IPSubnetCalc.numerize(ipAddress: self.ipv4Address), radix: 2)) - print("Mask bin : " + String(IPSubnetCalc.numerize(maskbits: self.maskBits), radix: 2)) + print("IP number in binary : " + String(IPSubnetCalc.digitize(ipAddress: self.ipv4Address), radix: 2)) + print("Mask bin : " + String(IPSubnetCalc.digitize(maskbits: self.maskBits), radix: 2)) //print("Subnet ID bin : " + String(self.subnetId(), radix: 2)) //print("Broadcast bin : " + String(self.subnetBroadcast(), radix: 2)) } @@ -545,6 +775,17 @@ class IPSubnetCalc: NSObject { //************* //IPv6 SECTION //************* + /** + Check if the IP address is a valid IPv6 address + + - Parameters: + - ipAddress: IPv6 address in hexadecimal format + - mask: Optionnal subnet mask + + - Returns: + Boolean if the given IPv6 address is valid or not + + */ static func isValidIPv6(ipAddress: String, mask: Int?) -> Bool { var ip4Hex: [String]? var hex: UInt16? @@ -601,10 +842,21 @@ class IPSubnetCalc: NSObject { return true } + /** + Convert an IPv4 address to its IPv6 address + + - Parameters: + - ipAddress: IPv4 address in dotted decimal format + - _6to4: Use 6to4 representation + + - Returns: + translated IPv6 address + + */ static func convertIPv4toIPv6(ipAddress: String, _6to4: Bool = false) -> String { var ipv6str = String() - let addr = numerize(ipAddress: ipAddress) + let addr = digitize(ipAddress: ipAddress) ipv6str.append(String((((Constants.addr32Digit1 | Constants.addr32Digit2) & addr) >> 16), radix: 16)) ipv6str.append(":") ipv6str.append(String(((Constants.addr32Digit3 | Constants.addr32Digit4) & addr), radix: 16)) @@ -615,6 +867,15 @@ class IPSubnetCalc: NSObject { return ("0:0:0:0:0:ffff:" + ipv6str) } + /** + Convert an IPv6 address to its IPv4 address + + - Parameter ipAddress: IPv6 address in hexadecimal format + + - Returns: + translated IPv4 address and detected translation method (6to4 or IPv4-Mapped) + + */ static func convertIPv6toIPv4(ipAddress: String) -> (String, String) { var ipv4str = String() //let ip4Hex = fullAddressIPv6(ipAddress: ipAddress).components(separatedBy: ":") @@ -663,11 +924,20 @@ class IPSubnetCalc: NSObject { } } - static func numerizeIPv6(ipAddress: String) -> [UInt16] { + /** + Convert an IPv6 address in hexadecimal format to its digital format + + - Parameter ipAddress: an IPv6 address in hexadecimal format. Must be in full format. + + - Returns: + UInt16 array of each digitized IPv6 address hexa segments + + */ + static func digitizeIPv6(ipAddress: String) -> [UInt16] { var ipAddressNum: [UInt16] = Array(repeating: 0, count: 8) var ip4Hex = [String]() - ip4Hex = ipAddress.components(separatedBy: ":") + ip4Hex = IPSubnetCalc.fullAddressIPv6(ipAddress: ipAddress).components(separatedBy: ":") for index in 0...(ip4Hex.count - 1) { if (ip4Hex[index] == "") { ip4Hex[index] = "0" @@ -678,6 +948,16 @@ class IPSubnetCalc: NSObject { return (ipAddressNum) } + /** + Convert an IPv6 address in its binary representation + + - Parameters: + - ipAddress: IPv6 address in hexadecimal format + - delimiter: add ':' to each hexa segment + + - Returns: + the binary representation of the given IPv6 address + */ static func binarizeIPv6(ipAddress: String, delimiter: Bool = false) -> String { var ip4Hex: [String] var binary: String @@ -698,7 +978,16 @@ class IPSubnetCalc: NSObject { return (binStr) } - static func numerizeMaskIPv6(maskbits: Int) -> [UInt16] { + /** + Convert an IPv6 mask value in bits to its digitized UInt16 array value + + - Parameter maskbits: subnet mask bits as in /XX notation + + - Returns: + a digital subnet mask in [UInt16] format + + */ + static func digitizeMaskIPv6(maskbits: Int) -> [UInt16] { var maskNum: [UInt16] = Array(repeating: 0, count: 8) for i in 0...7 { @@ -718,6 +1007,18 @@ class IPSubnetCalc: NSObject { return (maskNum) } + /** + Convert a digitized IPv6 address in its hexadecimal representation + + - Parameters: + - num: IPv6 address in its digitized format + - full: return a full representation (non compact) of the IPv6 address + - column: add ':' at each hexa segment + + - Returns: + the hexadecimal representation of the given IPv6 address + + */ static func hexarizeIPv6(num: [UInt16], full: Bool = true, column: Bool = false) -> String { var hex: String var hexStr = String() @@ -735,33 +1036,41 @@ class IPSubnetCalc: NSObject { return (hexStr) } + /** + Returns the Hexadecimal ID of IPv6 address + + - Returns: + the hexadecimal ID of the current IPv6 address + + */ func hexaIDIPv6() -> String { - var hexID: String = fullAddressIPv6(ipAddress: self.ipv6Address) + var hexID: String = IPSubnetCalc.fullAddressIPv6(ipAddress: self.ipv6Address) let delimiter: Set = [":"] hexID.removeAll(where: { delimiter.contains($0) }) return("0x\(hexID)") } + /** + Returns the binary representation of IPv6 address + + - Returns: + the binary representation of the current IPv6 address + + */ func binaryIDIPv6() -> String { return (IPSubnetCalc.binarizeIPv6(ipAddress: self.ipv6Address)) } - func digitizeIPv6() -> String { - var digitStr = String() - let numIP = IPSubnetCalc.numerizeIPv6(ipAddress: self.ipv6Address) - - for index in 0...7 { - if (index != 7) { - digitStr.append("\(numIP[index]):") - } - else { - digitStr.append("\(numIP[index])") - } - } - return (digitStr) - } - - func fullAddressIPv6(ipAddress: String) -> String { + /** + Convert a IPv6 address to its long notation + + - Parameter ipAddress: IPv6 address in hexadecimal format + + - Returns: + the long notation (non compact) of the given IPv6 address + + */ + static func fullAddressIPv6(ipAddress: String) -> String { var fullAddr = String() var ip4Hex = [String]() var prevIsZero = false @@ -791,7 +1100,16 @@ class IPSubnetCalc: NSObject { return (fullAddr) } - func compactAddressIPv6(ipAddress: String) -> String { + /** + Convert a IPv6 address to its compact/short notation + + - Parameter ipAddress: IPv6 address in hexadecimal format + + - Returns: + the compact notation of the given IPv6 address + + */ + static func compactAddressIPv6(ipAddress: String) -> String { var shortAddr = String() var ip4Hex = [String]() var prevIsZero = false @@ -800,7 +1118,7 @@ class IPSubnetCalc: NSObject { var prevNonZero = false //print("IP Address: \(ipAddress)") - ip4Hex = self.fullAddressIPv6(ipAddress: ipAddress).components(separatedBy: ":") + ip4Hex = IPSubnetCalc.fullAddressIPv6(ipAddress: ipAddress).components(separatedBy: ":") for index in 0...(ip4Hex.count - 1) { if (UInt16(ip4Hex[index], radix: 16)! == 0) { if (!prevIsZero || prevCompactZero) { @@ -848,10 +1166,17 @@ class IPSubnetCalc: NSObject { return (shortAddr) } + /** + Returns IPv6 Network address + + - Returns: + the Network address in hexadecimal format of the current IPv6 address + + */ func networkIPv6() -> String { var netID = [UInt16]() - let numMask = IPSubnetCalc.numerizeMaskIPv6(maskbits: self.ipv6MaskBits) - let numIP = IPSubnetCalc.numerizeIPv6(ipAddress: fullAddressIPv6(ipAddress: self.ipv6Address)) + let numMask = IPSubnetCalc.digitizeMaskIPv6(maskbits: self.ipv6MaskBits) + let numIP = IPSubnetCalc.digitizeIPv6(ipAddress: self.ipv6Address) for index in 0...7 { //print("Index: \(index) IP: \(numIP[index]) Mask : \(numMask[index]) Result : \(numIP[index] & (numMask[index])) ") @@ -860,11 +1185,18 @@ class IPSubnetCalc: NSObject { return (IPSubnetCalc.hexarizeIPv6(num: netID, full: false, column: true)) } + /** + Returns IPv6 Network Range + + - Returns: + First IPv6 address - Last IPv6 address of the current IPv6 address/mask + + */ func networkRangeIPv6() -> String { var netID = [UInt16]() var netID2 = [UInt16]() - let numMask = IPSubnetCalc.numerizeMaskIPv6(maskbits: self.ipv6MaskBits) - let numIP = IPSubnetCalc.numerizeIPv6(ipAddress: self.ipv6Address) + let numMask = IPSubnetCalc.digitizeMaskIPv6(maskbits: self.ipv6MaskBits) + let numIP = IPSubnetCalc.digitizeIPv6(ipAddress: self.ipv6Address) for index in 0...7 { //print("Index: \(index) IP: \(numIP[index]) Mask : \(numMask[index]) Result : \(numIP[index] & (numMask[index])) ") @@ -879,6 +1211,13 @@ class IPSubnetCalc: NSObject { return (netIDStr) } + /** + Returns Total IP addresses for IPv6 + + - Returns: + Total IP addresses for the current IPv6 mask + + */ func totalIPAddrIPv6() -> Decimal { var total = Decimal() var number: Decimal = 2 @@ -887,10 +1226,17 @@ class IPSubnetCalc: NSObject { return (total) } + /** + Returns IPv6 address in dotted decimal format + + - Returns: + IPv6 address in dotted decimal format of the current IPv6 address + + */ func dottedDecimalIPv6() -> String { var ipv4str = String() - let ip4Hex = fullAddressIPv6(ipAddress: self.ipv6Address).components(separatedBy: ":") + let ip4Hex = IPSubnetCalc.fullAddressIPv6(ipAddress: self.ipv6Address).components(separatedBy: ":") for index in (0...(ip4Hex.count - 1)) { if (index != 0) { ipv4str.append(".") @@ -907,8 +1253,15 @@ class IPSubnetCalc: NSObject { return ipv4str } + /** + Returns IPv6 address in IP6 ARPA notation + + - Returns: + IPv6 address in IP6 ARPA notation of the current IPv6 address + + */ func ip6ARPA () -> String { - var ipARPA = fullAddressIPv6(ipAddress: self.ipv6Address) + var ipARPA = IPSubnetCalc.fullAddressIPv6(ipAddress: self.ipv6Address) let delimiter: Set = [":"] ipARPA.removeAll(where: { delimiter.contains($0) }) @@ -923,12 +1276,19 @@ class IPSubnetCalc: NSObject { return (ipARPA) } + /** + Returns the reserved IPv6 block name if it exists + + - Returns: + reserved IPv6 block name or nil if it does not exist + + */ func resBlockIPv6() -> String? { var netID = networkIPv6() - netID = fullAddressIPv6(ipAddress: netID) + netID = IPSubnetCalc.fullAddressIPv6(ipAddress: netID) //print("NetID BEFORE compact : \(netID)") - netID = compactAddressIPv6(ipAddress: netID) + netID = IPSubnetCalc.compactAddressIPv6(ipAddress: netID) //print("NetID AFTER compact : \(netID)") netID.append("/\(self.ipv6MaskBits)") @@ -940,6 +1300,17 @@ class IPSubnetCalc: NSObject { return nil } + /** + Initialize an IPv4 object + + - Parameters: + - ipAddress: IPv4 address in its dotted decimal format + - maskbits: number of mask bits as in /XX notation + + - Returns: + nil if the IPv4 address or mask is not valid + + */ init?(ipAddress: String, maskbits: Int) { if (IPSubnetCalc.isValidIP(ipAddress: ipAddress, mask: String(maskbits), classless: true)) { self.ipv4Address = ipAddress @@ -952,6 +1323,16 @@ class IPSubnetCalc: NSObject { } } + /** + Initialize an IPv4 object with the default mask of its network class + + - Parameters: + - ipAddress: IPv4 address in its dotted decimal format + + - Returns: + nil if the IPv4 address is not valid + + */ convenience init?(_ ipAddress: String) { var classbit: Int @@ -973,6 +1354,17 @@ class IPSubnetCalc: NSObject { } } + /** + Initialize an IPv6 object + + - Parameters: + - ipv6: IPv6 address in its hexadecimal format + - maskbits: number of mask bits as in /XX notation + + - Returns: + nil if the IPv6 address or mask is not valid + + */ init?(ipv6: String, maskbits: Int) { if (IPSubnetCalc.isValidIPv6(ipAddress: ipv6, mask: maskbits)) { (self.ipv4Address, _) = IPSubnetCalc.convertIPv6toIPv4(ipAddress: ipv6) diff --git a/README.md b/README.md index 35b750f..642e77b 100644 --- a/README.md +++ b/README.md @@ -1,8 +1,8 @@ # SubnetCalc Subnet Calculator for MacOS -What's New in version 2.3: -- FLSM subnet ID bug fix +What's New in version 2.4: +- IPv6 address range bug fix diff --git a/SubnetCalc.xcodeproj/project.pbxproj b/SubnetCalc.xcodeproj/project.pbxproj index 40b2d6e..84f7848 100644 --- a/SubnetCalc.xcodeproj/project.pbxproj +++ b/SubnetCalc.xcodeproj/project.pbxproj @@ -401,7 +401,7 @@ CODE_SIGN_IDENTITY = "Mac Developer"; COMBINE_HIDPI_IMAGES = YES; COPY_PHASE_STRIP = NO; - CURRENT_PROJECT_VERSION = 9; + CURRENT_PROJECT_VERSION = 10; DEVELOPMENT_TEAM = VNLK894MAE; ENABLE_HARDENED_RUNTIME = YES; GCC_DYNAMIC_NO_PIC = NO; @@ -411,7 +411,7 @@ INFOPLIST_FILE = "SubnetCalc-Info.plist"; INSTALL_PATH = "$(HOME)/Applications"; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks"; - MARKETING_VERSION = 2.3; + MARKETING_VERSION = 2.4; PRODUCT_BUNDLE_IDENTIFIER = net.mulot.subnetcalc; PRODUCT_NAME = SubnetCalc; PROVISIONING_PROFILE_SPECIFIER = ""; @@ -430,7 +430,7 @@ CODE_SIGN_ENTITLEMENTS = SubnetCalc.entitlements; CODE_SIGN_IDENTITY = "Mac Developer"; COMBINE_HIDPI_IMAGES = YES; - CURRENT_PROJECT_VERSION = 9; + CURRENT_PROJECT_VERSION = 10; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; DEVELOPMENT_TEAM = VNLK894MAE; ENABLE_HARDENED_RUNTIME = YES; @@ -439,7 +439,7 @@ INFOPLIST_FILE = "SubnetCalc-Info.plist"; INSTALL_PATH = /Applications; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks"; - MARKETING_VERSION = 2.3; + MARKETING_VERSION = 2.4; PRODUCT_BUNDLE_IDENTIFIER = net.mulot.subnetcalc; PRODUCT_NAME = SubnetCalc; PROVISIONING_PROFILE_SPECIFIER = ""; diff --git a/SubnetCalcAppDelegate.swift b/SubnetCalcAppDelegate.swift index 3d18828..0c42401 100644 --- a/SubnetCalcAppDelegate.swift +++ b/SubnetCalcAppDelegate.swift @@ -10,6 +10,9 @@ import Cocoa @main class SubnetCalcAppDelegate: NSObject, NSApplicationDelegate, NSWindowDelegate, NSTableViewDataSource { + //******************* + //Private Constants + //******************* private enum Constants { static let defaultIP: String = "10.0.0.0" static let defaultIPv6Mask: String = "64" @@ -19,8 +22,9 @@ class SubnetCalcAppDelegate: NSObject, NSApplicationDelegate, NSWindowDelegate, static let NETWORK_BITS_MIN:Int = 8 static let NETWORK_BITS_MAX:Int = 32 } - + //******************* //General UI elements + //******************* @IBOutlet var window: NSWindow! @IBOutlet var addrField: NSTextField! @IBOutlet var exportButton: NSPopUpButton! @@ -28,7 +32,9 @@ class SubnetCalcAppDelegate: NSObject, NSApplicationDelegate, NSWindowDelegate, @IBOutlet var darkModeMenu: NSMenuItem! @IBOutlet var NSApp: NSApplication! + //**************** //IPv4 UI elements + //**************** @IBOutlet var classBinaryMap: NSTextField! @IBOutlet var classBitMap: NSTextField! @IBOutlet var classHexaMap: NSTextField! @@ -65,7 +71,9 @@ class SubnetCalcAppDelegate: NSObject, NSApplicationDelegate, NSWindowDelegate, @IBOutlet var subnetNameVLSM: NSTextField! @IBOutlet var viewVLSM: NSTableView! + //**************** //IPv6 UI elements + //**************** @IBOutlet var ipv6Address: NSTextField! @IBOutlet var ipv6to4Address: NSTextField! @IBOutlet var ipv6maskBitsCombo: NSComboBox! @@ -80,21 +88,26 @@ class SubnetCalcAppDelegate: NSObject, NSApplicationDelegate, NSWindowDelegate, @IBOutlet var ipv6Compact: NSButton! @IBOutlet var ipv6to4Box: NSBox! - + //******************* //Private global vars + //******************* private var ipsc: IPSubnetCalc? private var subnetsVLSM = [(Int, String, String)]() private var globalMaskVLSM: UInt32! - + //********************** //Private IPv4 functions + //********************** + /** + Init IPv4 CIDR Tab combo lists + */ private func initCIDRTab() { for bits in (1...32) { supernetMaskBitsCombo.addItem(withObjectValue: String(bits)) } for index in (0...31).reversed() { - supernetMaskCombo.addItem(withObjectValue: IPSubnetCalc.digitize(ipAddress: (IPSubnetCalc.Constants.addr32Full << index))) + supernetMaskCombo.addItem(withObjectValue: IPSubnetCalc.dottedDecimal(ipAddress: (IPSubnetCalc.Constants.addr32Full << index))) } for index in (0...31) { supernetMaxCombo.addItem(withObjectValue: NSDecimalNumber(decimal: pow(2, index)).stringValue) @@ -107,13 +120,16 @@ class SubnetCalcAppDelegate: NSObject, NSApplicationDelegate, NSWindowDelegate, } } + /** + Init IPv4 Tab combo lists + */ private func initSubnetsTab() { for index in (0...24).reversed() { if (wildcard.state == NSControl.StateValue.on) { - subnetMaskCombo.addItem(withObjectValue: IPSubnetCalc.digitize(ipAddress: ~(IPSubnetCalc.Constants.addr32Full << index))) + subnetMaskCombo.addItem(withObjectValue: IPSubnetCalc.dottedDecimal(ipAddress: ~(IPSubnetCalc.Constants.addr32Full << index))) } else { - subnetMaskCombo.addItem(withObjectValue: IPSubnetCalc.digitize(ipAddress: (IPSubnetCalc.Constants.addr32Full << index))) + subnetMaskCombo.addItem(withObjectValue: IPSubnetCalc.dottedDecimal(ipAddress: (IPSubnetCalc.Constants.addr32Full << index))) } } for bits in (8...32) { @@ -133,6 +149,9 @@ class SubnetCalcAppDelegate: NSObject, NSApplicationDelegate, NSWindowDelegate, classHexaMap.stringValue = "01.00.00.00" } + /** + Init FLSM Tab + */ private func initFLSMTab() { for bits in (8...32) { maskBitsFLSMCombo.addItem(withObjectValue: String(bits)) @@ -140,12 +159,18 @@ class SubnetCalcAppDelegate: NSObject, NSApplicationDelegate, NSWindowDelegate, slideFLSM.integerValue = 1 } + /** + Init VLSM Tab + */ private func initVLSMTab() { for bits in (8...32) { maskBitsVLSMCombo.addItem(withObjectValue: String(bits)) } } + /** + Init mask bits number of the Mask Bits slide on Subnets/Hosts Tab + */ private func bitsOnSlidePos() { var coordLabel = bitsOnSlide.frame @@ -155,6 +180,11 @@ class SubnetCalcAppDelegate: NSObject, NSApplicationDelegate, NSWindowDelegate, bitsOnSlide.frame = coordLabel } + /** + Select Address Class Type on IPv4 Tab + + - Parameter c: Class type of the IPv4 address: A, B, C, D or E + */ private func initClassInfos(_ c: String) { if (c == "A") @@ -179,6 +209,15 @@ class SubnetCalcAppDelegate: NSObject, NSApplicationDelegate, NSWindowDelegate, } } + /** + Split the given Address to its IP and mask + + - Parameters address: IP Address with or without its mask as /XX notation + + - Returns: + First String: IP Address. Second String: mask bits number + + */ private func splitAddrMask(address: String) -> (String, String?) { let ipInfo = address.split(separator: "/") if ipInfo.count == 2 { @@ -191,6 +230,9 @@ class SubnetCalcAppDelegate: NSObject, NSApplicationDelegate, NSWindowDelegate, return (address, nil) } + /** + Generate the Binary Map, Bits Maps and Hexa Map of the current IP + */ private func doAddressMap() { if (ipsc != nil) { self.initClassInfos(ipsc!.netClass()) @@ -207,6 +249,9 @@ class SubnetCalcAppDelegate: NSObject, NSApplicationDelegate, NSWindowDelegate, } } + /** + Generate infos of the IPv4 Tab for the current IP and mask + */ private func doSubnet() { if (ipsc != nil) { @@ -226,6 +271,9 @@ class SubnetCalcAppDelegate: NSObject, NSApplicationDelegate, NSWindowDelegate, } } + /** + Generate infos of the Subnets/Hosts Tab for the current IP and mask + */ private func doSubnetHost() { if (ipsc != nil) { @@ -236,6 +284,9 @@ class SubnetCalcAppDelegate: NSObject, NSApplicationDelegate, NSWindowDelegate, } } + /** + Generate infos of the FLSM Tab for the current IP and mask + */ private func doFLSM() { if (ipsc != nil) { @@ -256,19 +307,22 @@ class SubnetCalcAppDelegate: NSObject, NSApplicationDelegate, NSWindowDelegate, } } + /** + Generate infos of the VLSM Tab for the current IP and mask if there are some Hosts requirements + */ private func doVLSM() { if (ipsc != nil) { //print("doVLSM") maskBitsVLSMCombo.selectItem(withObjectValue: String(ipsc!.maskBits)) - var maskVLSM = ~IPSubnetCalc.numerize(maskbits: ipsc!.maskBits) + 1 + var maskVLSM = ~IPSubnetCalc.digitize(maskbits: ipsc!.maskBits) + 1 if (subnetsVLSM.count != 0) { var fitsRequirements = true for index in (0...(subnetsVLSM.count - 1)) { let maskbits = subnetsVLSM[index].0 //print("Mask VLSM: \(IPSubnetCalc.digitize(ipAddress: maskVLSM)) Maskbits: \(IPSubnetCalc.digitize(ipAddress: ~IPSubnetCalc.numerize(maskbits: maskbits)))") - if (maskVLSM > ~IPSubnetCalc.numerize(maskbits: maskbits)) { - maskVLSM = maskVLSM - (~IPSubnetCalc.numerize(maskbits: maskbits) + 1) + if (maskVLSM > ~IPSubnetCalc.digitize(maskbits: maskbits)) { + maskVLSM = maskVLSM - (~IPSubnetCalc.digitize(maskbits: maskbits) + 1) //print("Mask AFTER VLSM: \(IPSubnetCalc.digitize(ipAddress: maskVLSM))") } else { @@ -289,6 +343,12 @@ class SubnetCalcAppDelegate: NSObject, NSApplicationDelegate, NSWindowDelegate, } } + /** + Generate infos of the CIDR Tab + + - Parameter maskbits: mask bits number + + */ private func doCIDR(maskbits: Int? = nil) { if (ipsc != nil) { @@ -316,6 +376,14 @@ class SubnetCalcAppDelegate: NSObject, NSApplicationDelegate, NSWindowDelegate, } } + /** + Display an alert window pop-up with customs message and info + + - Parameters: + - message: Main displayed message + - info: message info + + */ private func myAlert(message: String, info: String) { let alert = NSAlert() @@ -326,6 +394,13 @@ class SubnetCalcAppDelegate: NSObject, NSApplicationDelegate, NSWindowDelegate, alert.runModal() } + /** + Generate infos for all IPv4 tabs. + + Check if there is are current IP address and mask otherwise take the default IP and mask. + + Check if the IP address and mask are valid. + */ private func doIPSubnetCalc() { var ipaddr: String @@ -388,7 +463,12 @@ class SubnetCalcAppDelegate: NSObject, NSApplicationDelegate, NSWindowDelegate, } } + //********************** //Private IPv6 functions + //********************** + /** + Init IPv6 Tab combo lists + */ private func initIPv6Tab() { var total = Decimal() var number: Decimal = 2 @@ -402,6 +482,9 @@ class SubnetCalcAppDelegate: NSObject, NSApplicationDelegate, NSWindowDelegate, } } + /** + Generate info for IPv6 tab + */ private func doIPv6() { if (ipsc != nil) { @@ -410,12 +493,12 @@ class SubnetCalcAppDelegate: NSObject, NSApplicationDelegate, NSWindowDelegate, var typeConv: String if (ipv6Compact.state == NSControl.StateValue.on) { - ipv6Address.stringValue = ipsc!.compactAddressIPv6(ipAddress: ipsc!.ipv6Address) - ipv6Network.stringValue = ipsc!.compactAddressIPv6(ipAddress: ipsc!.networkIPv6()) + ipv6Address.stringValue = IPSubnetCalc.compactAddressIPv6(ipAddress: ipsc!.ipv6Address) + ipv6Network.stringValue = IPSubnetCalc.compactAddressIPv6(ipAddress: ipsc!.networkIPv6()) } else { - ipv6Address.stringValue = ipsc!.fullAddressIPv6(ipAddress: ipsc!.ipv6Address) - ipv6Network.stringValue = ipsc!.fullAddressIPv6(ipAddress: ipsc!.networkIPv6()) + ipv6Address.stringValue = IPSubnetCalc.fullAddressIPv6(ipAddress: ipsc!.ipv6Address) + ipv6Network.stringValue = IPSubnetCalc.fullAddressIPv6(ipAddress: ipsc!.networkIPv6()) } (ipv6to4Address.stringValue, typeConv) = IPSubnetCalc.convertIPv6toIPv4(ipAddress: ipsc!.ipv6Address) ipv6to4Box.title = "IPv4 conversion" + " (\(typeConv))" @@ -440,6 +523,13 @@ class SubnetCalcAppDelegate: NSObject, NSApplicationDelegate, NSWindowDelegate, } } + /** + Generate infos for IPv6 tab + + Genrate infos also for all IPv4 tabs based on the converted IPv4 address + + Check if the IPv6 address and mask are valid. + */ private func doIPv6SubnetCalc() { var ipaddr: String @@ -485,8 +575,15 @@ class SubnetCalcAppDelegate: NSObject, NSApplicationDelegate, NSWindowDelegate, } } - + //*************** //IPv4 UI actions + //*************** + /** + Triggered when the user has changed the Network Class type in the IPv4 tab + + - Parameter sender: Class type selected by the user + + */ @IBAction func changeAddrClassType(_ sender: AnyObject) { if (sender.indexOfSelectedItem() == 0) @@ -521,6 +618,12 @@ class SubnetCalcAppDelegate: NSObject, NSApplicationDelegate, NSWindowDelegate, } } + /** + Triggered when the user has changed the Max Hosts / Subnet item in the IPv4 tab + + - Parameter sender: selected item of the Max Hosts / Subnet list + + */ @IBAction func changeMaxHosts(_ sender: AnyObject) { if (ipsc == nil) @@ -537,6 +640,12 @@ class SubnetCalcAppDelegate: NSObject, NSApplicationDelegate, NSWindowDelegate, } } + /** + Triggered when the user has changed the Max Subnets item in the IPv4 tab + + - Parameter sender: selected item of the Max Subnets list + + */ @IBAction func changeMaxSubnets(_ sender: AnyObject) { if (ipsc == nil) @@ -553,6 +662,12 @@ class SubnetCalcAppDelegate: NSObject, NSApplicationDelegate, NSWindowDelegate, } } + /** + Triggered when the user has changed the Subnets Bits item in the IPv4 tab + + - Parameter sender: selected item of the Subnets Bits list + + */ @IBAction func changeSubnetBits(_ sender: AnyObject) { if (ipsc == nil) @@ -569,6 +684,12 @@ class SubnetCalcAppDelegate: NSObject, NSApplicationDelegate, NSWindowDelegate, } } + /** + Triggered when the user has changed the Subnet Mask item in the IPv4 tab + + - Parameter sender: selected item of the Subnet Mask list + + */ @IBAction func changeSubnetMask(_ sender: AnyObject) { if (ipsc == nil) @@ -577,7 +698,7 @@ class SubnetCalcAppDelegate: NSObject, NSApplicationDelegate, NSWindowDelegate, } // Check cast as String needed ? if let maskStr = sender.objectValueOfSelectedItem as? String { - let mask:UInt32 = IPSubnetCalc.numerize(ipAddress: maskStr) + let mask:UInt32 = IPSubnetCalc.digitize(ipAddress: maskStr) if (wildcard.state == NSControl.StateValue.on) { ipsc!.maskBits = IPSubnetCalc.maskBits(mask: ~mask) } @@ -593,6 +714,12 @@ class SubnetCalcAppDelegate: NSObject, NSApplicationDelegate, NSWindowDelegate, } } + /** + Triggered when the user has changed the Mask Bits item in the IPv4 tab + + - Parameter sender: selected item of the Mask Bits list + + */ @IBAction func changeMaskBits(_ sender: AnyObject) { if (ipsc == nil) @@ -609,6 +736,12 @@ class SubnetCalcAppDelegate: NSObject, NSApplicationDelegate, NSWindowDelegate, } } + /** + Triggered when the user has changed the Mask Bits item in the CIDR tab + + - Parameter sender: selected item of the Mask Bits list + + */ @IBAction func changeSupernetMaskBits(_ sender: AnyObject) { if (ipsc == nil) @@ -642,6 +775,12 @@ class SubnetCalcAppDelegate: NSObject, NSApplicationDelegate, NSWindowDelegate, } } + /** + Triggered when the user has changed the Mask item in the CIDR tab + + - Parameter sender: selected item of the Mask list + + */ @IBAction func changeSupernetMask(_ sender: AnyObject) { if (ipsc == nil) @@ -649,7 +788,7 @@ class SubnetCalcAppDelegate: NSObject, NSApplicationDelegate, NSWindowDelegate, ipsc = IPSubnetCalc(Constants.defaultIP) } if let maskStr = sender.objectValueOfSelectedItem as? String { - let mask:UInt32 = IPSubnetCalc.numerize(ipAddress: maskStr) + let mask:UInt32 = IPSubnetCalc.digitize(ipAddress: maskStr) let maskbits:Int = IPSubnetCalc.maskBits(mask: mask) let classType = ipsc!.netClass() var result: Int = -1 @@ -677,6 +816,12 @@ class SubnetCalcAppDelegate: NSObject, NSApplicationDelegate, NSWindowDelegate, } } + /** + Triggered when the user has changed the Max Supernets item in the CIDR tab + + - Parameter sender: selected item of the Max Supernets list + + */ @IBAction func changeSupernetMax(_ sender: AnyObject) { if (ipsc == nil) @@ -710,6 +855,12 @@ class SubnetCalcAppDelegate: NSObject, NSApplicationDelegate, NSWindowDelegate, } } + /** + Triggered when the user has changed the Max Addresses item in the CIDR tab + + - Parameter sender: selected item of the Max Addresses list + + */ @IBAction func changeSupernetMaxAddr(_ sender: AnyObject) { if (ipsc == nil) @@ -731,6 +882,12 @@ class SubnetCalcAppDelegate: NSObject, NSApplicationDelegate, NSWindowDelegate, } } + /** + Triggered when the user has changed the Max Subnets item in the CIDR tab + + - Parameter sender: selected item of the Max Subnets list + + */ @IBAction func changeSupernetMaxSubnets(_ sender: AnyObject) { if (ipsc == nil) @@ -752,6 +909,15 @@ class SubnetCalcAppDelegate: NSObject, NSApplicationDelegate, NSWindowDelegate, } } + /** + Returns the number of rows for the NSTableView to display + + - Parameter tableView: NSTableView to display + + - Returns: + Number of rows to display in the given NSTableView + + */ func numberOfRows(in tableView: NSTableView) -> Int { if (ipsc != nil) { @@ -776,8 +942,18 @@ class SubnetCalcAppDelegate: NSObject, NSApplicationDelegate, NSWindowDelegate, return 0 } - //Invoked when editing a value from a TabView - //Used only for VLSM Subnet Name + /** + Auto invoked when editing a value from a TabView + + Used only for VLSM Subnet Name + + - Parameters: + - tableView: NSTableView + - object: new String value for the edited object + - tableColumn: Optionnal Column + - row: row index + + */ func tableView(_ tableView: NSTableView, setObjectValue object: Any?, for tableColumn: NSTableColumn?, row: Int) { if (tableView == viewVLSM) { @@ -788,15 +964,25 @@ class SubnetCalcAppDelegate: NSObject, NSApplicationDelegate, NSWindowDelegate, } } - //Display all subnets info in the TableView Subnet/Hosts + /** + Display all subnets info in the TableView Subnet/Hosts + + - Parameters: + - tableView: NSTableView + - tableColumn: Optionnal Column + - row: row index + + - Returns: + Object to display for the correponding column and row + */ func tableView(_ tableView: NSTableView, objectValueFor tableColumn: NSTableColumn?, row: Int) -> Any? { if (ipsc != nil) { //print("Refresh TableView: \(String(describing: tableView.identifier))") if (tableView == subnetsHostsView) { - let ipaddr: UInt32 = (((IPSubnetCalc.numerize(ipAddress: ipsc!.ipv4Address) & ipsc!.classMask()) >> (32 - ipsc!.maskBits)) + UInt32(row)) << (32 - ipsc!.maskBits) - let ipsc_tmp = IPSubnetCalc(ipAddress: IPSubnetCalc.digitize(ipAddress: ipaddr), maskbits: ipsc!.maskBits) + let ipaddr: UInt32 = (((IPSubnetCalc.digitize(ipAddress: ipsc!.ipv4Address) & ipsc!.classMask()) >> (32 - ipsc!.maskBits)) + UInt32(row)) << (32 - ipsc!.maskBits) + let ipsc_tmp = IPSubnetCalc(ipAddress: IPSubnetCalc.dottedDecimal(ipAddress: ipaddr), maskbits: ipsc!.maskBits) //print("tableView Row: \(row) IP num : \(ipaddr) IP: \(IPSubnetCalc.digitize(ipAddress: ipaddr)) IP Subnet: \(ipsc_tmp!.subnetId())") if (tableColumn != nil && ipsc_tmp != nil) { if (tableColumn!.identifier.rawValue == "numCol") { @@ -815,9 +1001,9 @@ class SubnetCalcAppDelegate: NSObject, NSApplicationDelegate, NSWindowDelegate, } else if (tableView == viewFLSM) { //print("refresh View FLSM") - var ipaddr: UInt32 = ((IPSubnetCalc.numerize(ipAddress: ipsc!.ipv4Address) & IPSubnetCalc.numerize(maskbits: ipsc!.maskBits)) >> (32 - ipsc!.maskBits)) << (32 - ipsc!.maskBits) + var ipaddr: UInt32 = ((IPSubnetCalc.digitize(ipAddress: ipsc!.ipv4Address) & IPSubnetCalc.digitize(maskbits: ipsc!.maskBits)) >> (32 - ipsc!.maskBits)) << (32 - ipsc!.maskBits) ipaddr = (ipaddr >> (32 - (ipsc!.maskBits + slideFLSM.integerValue)) + UInt32(row)) << (32 - (ipsc!.maskBits + slideFLSM.integerValue)) - let ipsc_tmp = IPSubnetCalc(ipAddress: IPSubnetCalc.digitize(ipAddress: ipaddr), maskbits: (ipsc!.maskBits + slideFLSM.integerValue)) + let ipsc_tmp = IPSubnetCalc(ipAddress: IPSubnetCalc.dottedDecimal(ipAddress: ipaddr), maskbits: (ipsc!.maskBits + slideFLSM.integerValue)) if (tableColumn != nil && ipsc_tmp != nil) { if (tableColumn!.identifier.rawValue == "numFLSMCol") { return (row + 1) @@ -843,13 +1029,13 @@ class SubnetCalcAppDelegate: NSObject, NSApplicationDelegate, NSWindowDelegate, return (row + 1) } else if (tableColumn!.identifier.rawValue == "subnetVLSMCol") { - var subnet = IPSubnetCalc.numerize(ipAddress: ipsc!.subnetId()) + var subnet = IPSubnetCalc.digitize(ipAddress: ipsc!.subnetId()) if (row > 0) { for index in (0...(row - 1)) { - subnet = subnet + ~IPSubnetCalc.numerize(maskbits: subnetsVLSM[index].0) + 1 + subnet = subnet + ~IPSubnetCalc.digitize(maskbits: subnetsVLSM[index].0) + 1 } } - return (IPSubnetCalc.digitize(ipAddress: subnet)) + return (IPSubnetCalc.dottedDecimal(ipAddress: subnet)) } else if (tableColumn!.identifier.rawValue == "maskVLSMCol") { return (subnetsVLSM[row].0) @@ -861,26 +1047,26 @@ class SubnetCalcAppDelegate: NSObject, NSApplicationDelegate, NSWindowDelegate, return (subnetsVLSM[row].2) } else if (tableColumn!.identifier.rawValue == "rangeVLSMCol") { - var subnet = IPSubnetCalc.numerize(ipAddress: ipsc!.subnetId()) + var subnet = IPSubnetCalc.digitize(ipAddress: ipsc!.subnetId()) if (row > 0) { for index in (0...(row - 1)) { - subnet = subnet + ~IPSubnetCalc.numerize(maskbits: subnetsVLSM[index].0) + 1 + subnet = subnet + ~IPSubnetCalc.digitize(maskbits: subnetsVLSM[index].0) + 1 } } - let ipsc_tmp = IPSubnetCalc(ipAddress: IPSubnetCalc.digitize(ipAddress: subnet), maskbits: (subnetsVLSM[row].0)) + let ipsc_tmp = IPSubnetCalc(ipAddress: IPSubnetCalc.dottedDecimal(ipAddress: subnet), maskbits: (subnetsVLSM[row].0)) if (ipsc_tmp != nil) { return (ipsc_tmp!.subnetRange()) } } else if (tableColumn!.identifier.rawValue == "broadcastVLSMCol") { - var subnet = IPSubnetCalc.numerize(ipAddress: ipsc!.subnetId()) + var subnet = IPSubnetCalc.digitize(ipAddress: ipsc!.subnetId()) if (row > 0) { for index in (0...(row - 1)) { - subnet = subnet + ~IPSubnetCalc.numerize(maskbits: subnetsVLSM[index].0) + 1 + subnet = subnet + ~IPSubnetCalc.digitize(maskbits: subnetsVLSM[index].0) + 1 } } - let ipsc_tmp = IPSubnetCalc(ipAddress: IPSubnetCalc.digitize(ipAddress: subnet), maskbits: (subnetsVLSM[row].0)) + let ipsc_tmp = IPSubnetCalc(ipAddress: IPSubnetCalc.dottedDecimal(ipAddress: subnet), maskbits: (subnetsVLSM[row].0)) if (ipsc_tmp != nil) { return (ipsc_tmp!.subnetBroadcast()) @@ -891,7 +1077,13 @@ class SubnetCalcAppDelegate: NSObject, NSApplicationDelegate, NSWindowDelegate, } return (nil) } - + + /** + Triggered when the user has changed the Mask bits slide of the Subnets/Hosts tab + + - Parameter sender: current slide position + + */ @IBAction func subnetBitsSlide(_ sender: AnyObject) { if (ipsc == nil) @@ -917,6 +1109,12 @@ class SubnetCalcAppDelegate: NSObject, NSApplicationDelegate, NSWindowDelegate, } } + /** + Triggered when the user has changed the slide of the FLSM tab + + - Parameter sender: current slide position + + */ @IBAction func changeSlideFLSM(_ sender: AnyObject) { if (ipsc == nil) @@ -930,6 +1128,14 @@ class SubnetCalcAppDelegate: NSObject, NSApplicationDelegate, NSWindowDelegate, } } + /** + Triggered when the user has added a new hosts requirement in the VLSM tab + + Add a new number of hosts and an optionnal subnet name in the VLSM requirements list + + - Parameter sender: non used + + */ @IBAction func addSubnetVLSM(_ sender: AnyObject) { var maskbits: Int @@ -949,8 +1155,8 @@ class SubnetCalcAppDelegate: NSObject, NSApplicationDelegate, NSWindowDelegate, if (subnetsVLSM.count != 0) { //print("VLSM subnets NOT empty") //print("Mask VLSM: \(IPSubnetCalc.digitize(ipAddress: globalMaskVLSM)) Maskbits: \(IPSubnetCalc.digitize(ipAddress: ~IPSubnetCalc.numerize(maskbits: maskbits)))") - if (globalMaskVLSM > ~IPSubnetCalc.numerize(maskbits: maskbits)) { - globalMaskVLSM = globalMaskVLSM - (~IPSubnetCalc.numerize(maskbits: maskbits) + 1) + if (globalMaskVLSM > ~IPSubnetCalc.digitize(maskbits: maskbits)) { + globalMaskVLSM = globalMaskVLSM - (~IPSubnetCalc.digitize(maskbits: maskbits) + 1) //print("Mask AFTER VLSM: \(IPSubnetCalc.digitize(ipAddress: globalMaskVLSM))") if let index = subnetsVLSM.firstIndex(where: { $0.0 > maskbits }) { subnetsVLSM.insert((maskbits, subnetNameVLSM.stringValue, "\(requiredHostsVLSM.stringValue)/\(hosts) (\(used)%)"), at: index) @@ -966,10 +1172,10 @@ class SubnetCalcAppDelegate: NSObject, NSApplicationDelegate, NSWindowDelegate, } else { //print("VLSM subnets empty") - globalMaskVLSM = ~IPSubnetCalc.numerize(maskbits: ipsc!.maskBits) + 1 + globalMaskVLSM = ~IPSubnetCalc.digitize(maskbits: ipsc!.maskBits) + 1 //print("Mask VLSM: \(IPSubnetCalc.digitize(ipAddress: globalMaskVLSM)) Maskbits: \(IPSubnetCalc.digitize(ipAddress: ~IPSubnetCalc.numerize(maskbits: maskbits)))") - if (globalMaskVLSM > ~IPSubnetCalc.numerize(maskbits: maskbits)) { - globalMaskVLSM = globalMaskVLSM - (~IPSubnetCalc.numerize(maskbits: maskbits) + 1) + if (globalMaskVLSM > ~IPSubnetCalc.digitize(maskbits: maskbits)) { + globalMaskVLSM = globalMaskVLSM - (~IPSubnetCalc.digitize(maskbits: maskbits) + 1) //print("Mask AFTER VLSM: \(IPSubnetCalc.digitize(ipAddress: globalMaskVLSM))") subnetsVLSM.append((maskbits, subnetNameVLSM.stringValue, "\(requiredHostsVLSM.stringValue)/\(hosts) (\(used)%)")) } @@ -988,6 +1194,14 @@ class SubnetCalcAppDelegate: NSObject, NSApplicationDelegate, NSWindowDelegate, subnetNameVLSM.stringValue = "" } + /** + Triggered when the user has deleted an existing subnet in the VLSM tab + + Remove the selected subnet in the VLSM requirements list + + - Parameter sender: non used + + */ @IBAction func deleteSubnetVLSM(_ sender: AnyObject) { if (subnetsVLSM.count != 0) { @@ -999,11 +1213,27 @@ class SubnetCalcAppDelegate: NSObject, NSApplicationDelegate, NSWindowDelegate, } } + /** + Triggered when the user has clicked on the clear button of the VLSM tab + + Remove all subnets in the VLSM requirements list + + - Parameter sender: non used + + */ @IBAction func clearSubnetsVLSM(_ sender: AnyObject) { subnetsVLSM.removeAll() doVLSM() } + /** + Triggered when the user has clicked on the CIDR option of the Subnets/Hosts tab + + Enable or disable the classless state. Allow or disallow the mask bits to be lower to the Network class bits. + + - Parameter sender: non used + + */ @IBAction func changeTableViewClass(_ sender: AnyObject) { if (tabViewClassLess.state == NSControl.StateValue.off) { @@ -1017,12 +1247,20 @@ class SubnetCalcAppDelegate: NSObject, NSApplicationDelegate, NSWindowDelegate, self.doSubnetHost() } + /** + Triggered when the user has clicked on the Wildcard option of the IPv4 tab + + Change the mask to the reverse notation (Cisco mask) in the Subnet Mask combo list + + - Parameter sender: non used + + */ @IBAction func changeWildcard(_ sender: AnyObject) { subnetMaskCombo.removeAllItems() if (wildcard.state == NSControl.StateValue.on) { for index in (0...24).reversed() { - subnetMaskCombo.addItem(withObjectValue: IPSubnetCalc.digitize(ipAddress: ~(IPSubnetCalc.Constants.addr32Full << index))) + subnetMaskCombo.addItem(withObjectValue: IPSubnetCalc.dottedDecimal(ipAddress: ~(IPSubnetCalc.Constants.addr32Full << index))) } if (ipsc != nil) { subnetMaskCombo.selectItem(withObjectValue: ipsc!.wildcardMask()) @@ -1030,7 +1268,7 @@ class SubnetCalcAppDelegate: NSObject, NSApplicationDelegate, NSWindowDelegate, } else { for index in (0...24).reversed() { - subnetMaskCombo.addItem(withObjectValue: IPSubnetCalc.digitize(ipAddress: (IPSubnetCalc.Constants.addr32Full << index))) + subnetMaskCombo.addItem(withObjectValue: IPSubnetCalc.dottedDecimal(ipAddress: (IPSubnetCalc.Constants.addr32Full << index))) } if (ipsc != nil) { subnetMaskCombo.selectItem(withObjectValue: ipsc!.subnetMask()) @@ -1038,17 +1276,42 @@ class SubnetCalcAppDelegate: NSObject, NSApplicationDelegate, NSWindowDelegate, } } + /** + Triggered when the user has clicked on the Dotted option of the IPv4 tab + + Add a dot at each IP address decimal in the Bit Map, Binary Map and Hexa Map + + - Parameter sender: non used + + */ @IBAction func changeDotted(_ sender: AnyObject) { self.doAddressMap() } + //*************** //IPv6 UI actions + //*************** + /** + Triggered when the user has clicked on the Short option of the IPv6 tab + + Display short/compact or long/full IPv6 address format + + - Parameter sender: non used + + */ @IBAction func changeIPv6Format(_ sender: AnyObject) { self.doIPv6() } + /** + Triggered when the user has changed the Mask bits of the IPv6 tab + + + - Parameter sender: selected item of the Mask bits list + + */ @IBAction func changeIPv6MaskBits(_ sender: AnyObject) { //print("changeIPv6MaskBits") @@ -1066,6 +1329,13 @@ class SubnetCalcAppDelegate: NSObject, NSApplicationDelegate, NSWindowDelegate, } } + /** + Triggered when the user has changed the Available Subnets of the IPv6 tab + + + - Parameter sender: selected item of the Available Subnets list + + */ @IBAction func changeIPv6Subnets(_ sender: AnyObject) { if (ipsc == nil ) { @@ -1075,6 +1345,13 @@ class SubnetCalcAppDelegate: NSObject, NSApplicationDelegate, NSWindowDelegate, self.doIPv6SubnetCalc() } + /** + Triggered when the user has changed the Max Hosts / Subnet of the IPv6 tab + + + - Parameter sender: selected item of the Max Hosts / Subnet list + + */ @IBAction func changeIPv6MaxHosts(_ sender: AnyObject) { if (ipsc == nil) @@ -1091,7 +1368,17 @@ class SubnetCalcAppDelegate: NSObject, NSApplicationDelegate, NSWindowDelegate, } } + //****************** //General UI actions + //****************** + /** + Perform IPv4/IPv6 calculation + + Triggered when the user has clicked on the Calc button + + - Parameter sender: non used + + */ @IBAction func calc(_ sender: AnyObject) { if (addrField.stringValue.contains(":")) { @@ -1104,11 +1391,26 @@ class SubnetCalcAppDelegate: NSObject, NSApplicationDelegate, NSWindowDelegate, } } + /** + Triggered when the user hit Enter key in the IP address field + + + - Parameter sender: sender of the action + + */ @IBAction func ipAddrEdit(_ sender: AnyObject) { self.calc(sender) } + /** + Export Subnet/Hosts tab infos to a CSV file + + Triggered when the user selects Export Subnets/Hosts + + - Parameter sender: non used + + */ @IBAction func exportSubnetsHosts(_ sender: AnyObject) { if (ipsc != nil) { @@ -1131,8 +1433,8 @@ class SubnetCalcAppDelegate: NSObject, NSApplicationDelegate, NSWindowDelegate, var cvsStr = "#;Subnet ID;Range;Broadcast\n" for index in (0...(self.ipsc!.maxSubnets() - 1)) { let mask: UInt32 = UInt32(index) << (32 - self.ipsc!.maskBits) - let ipaddr = (IPSubnetCalc.numerize(ipAddress: self.ipsc!.subnetId())) | mask - let ipsc_tmp = IPSubnetCalc(ipAddress: IPSubnetCalc.digitize(ipAddress: ipaddr), maskbits: self.ipsc!.maskBits) + let ipaddr = (IPSubnetCalc.digitize(ipAddress: self.ipsc!.subnetId())) | mask + let ipsc_tmp = IPSubnetCalc(ipAddress: IPSubnetCalc.dottedDecimal(ipAddress: ipaddr), maskbits: self.ipsc!.maskBits) if (ipsc_tmp != nil) { cvsStr.append("\(index + 1);\(ipsc_tmp!.subnetId());\(ipsc_tmp!.subnetRange());\(ipsc_tmp!.subnetBroadcast())\n") } @@ -1148,6 +1450,14 @@ class SubnetCalcAppDelegate: NSObject, NSApplicationDelegate, NSWindowDelegate, } } + /** + Export FLSM tab infos to a CSV file + + Triggered when the user selects Export FLSM + + - Parameter sender: non used + + */ @IBAction func exportFLSM(_ sender: AnyObject) { if (ipsc != nil) { @@ -1169,10 +1479,10 @@ class SubnetCalcAppDelegate: NSObject, NSApplicationDelegate, NSWindowDelegate, let cvsFile = FileHandle(forWritingAtPath: panel.url!.path) if (cvsFile != nil) { var cvsStr = "#;Subnet ID;Mask bits;Range;Broadcast\n" - let subnetid: UInt32 = ((IPSubnetCalc.numerize(ipAddress: self.ipsc!.ipv4Address) & IPSubnetCalc.numerize(maskbits: self.ipsc!.maskBits)) >> (32 - self.ipsc!.maskBits)) << (32 - self.ipsc!.maskBits) + let subnetid: UInt32 = ((IPSubnetCalc.digitize(ipAddress: self.ipsc!.ipv4Address) & IPSubnetCalc.digitize(maskbits: self.ipsc!.maskBits)) >> (32 - self.ipsc!.maskBits)) << (32 - self.ipsc!.maskBits) for index in (0...(Int(truncating: NSDecimalNumber(decimal: pow(2, self.slideFLSM.integerValue))) - 1)) { let ipaddr = (subnetid >> (32 - (self.ipsc!.maskBits + self.slideFLSM.integerValue)) + UInt32(index)) << (32 - (self.ipsc!.maskBits + self.slideFLSM.integerValue)) - let ipsc_tmp = IPSubnetCalc(ipAddress: IPSubnetCalc.digitize(ipAddress: ipaddr), maskbits: (self.ipsc!.maskBits + self.slideFLSM.integerValue)) + let ipsc_tmp = IPSubnetCalc(ipAddress: IPSubnetCalc.dottedDecimal(ipAddress: ipaddr), maskbits: (self.ipsc!.maskBits + self.slideFLSM.integerValue)) if (ipsc_tmp != nil) { cvsStr.append("\(index + 1);\(ipsc_tmp!.subnetId());\(self.ipsc!.maskBits + self.slideFLSM.integerValue);\(ipsc_tmp!.subnetRange());\(ipsc_tmp!.subnetBroadcast())\n") } @@ -1192,6 +1502,14 @@ class SubnetCalcAppDelegate: NSObject, NSApplicationDelegate, NSWindowDelegate, } } + /** + Export VLSM tab infos to a CSV file + + Triggered when the user selects Export VLSM + + - Parameter sender: non used + + */ @IBAction func exportVLSM(_ sender: AnyObject) { if (ipsc != nil) { @@ -1213,15 +1531,15 @@ class SubnetCalcAppDelegate: NSObject, NSApplicationDelegate, NSWindowDelegate, let cvsFile = FileHandle(forWritingAtPath: panel.url!.path) if (cvsFile != nil) { var cvsStr = "#;Subnet Name;Subnet ID;Mask bits;Hosts Range;Broadcast;Used\n" - let subnetid = IPSubnetCalc.numerize(ipAddress: self.ipsc!.subnetId()) + let subnetid = IPSubnetCalc.digitize(ipAddress: self.ipsc!.subnetId()) for index in (0...(self.subnetsVLSM.count - 1)) { var subnet = subnetid if (index > 0) { for index2 in (0...(index - 1)) { - subnet = subnet + ~IPSubnetCalc.numerize(maskbits: self.subnetsVLSM[index2].0) + 1 + subnet = subnet + ~IPSubnetCalc.digitize(maskbits: self.subnetsVLSM[index2].0) + 1 } } - let ipsc_tmp = IPSubnetCalc(ipAddress: IPSubnetCalc.digitize(ipAddress: subnet), maskbits: self.subnetsVLSM[index].0)! + let ipsc_tmp = IPSubnetCalc(ipAddress: IPSubnetCalc.dottedDecimal(ipAddress: subnet), maskbits: self.subnetsVLSM[index].0)! //print("VLSM: \(index + 1);\(IPSubnetCalc.digitize(ipAddress: subnet));\(self.subnetsVLSM[index].0);\(self.subnetsVLSM[index].1);\(self.subnetsVLSM[index].2)\n") cvsStr.append("\(index + 1);\(self.subnetsVLSM[index].1);\(ipsc_tmp.subnetId());\(self.subnetsVLSM[index].0);\(ipsc_tmp.subnetRange());\(ipsc_tmp.subnetBroadcast());\(self.subnetsVLSM[index].2)\n") } @@ -1240,17 +1558,35 @@ class SubnetCalcAppDelegate: NSObject, NSApplicationDelegate, NSWindowDelegate, } } + /** + Export IPv4 infos to the macOS clipboard + + Triggered when the user selects Export Clipboard + + - Parameter sender: non used + + */ @IBAction func exportClipboard(_ sender: AnyObject) { if (ipsc != nil) { let pb: NSPasteboard = NSPasteboard.general pb.clearContents() let ipv4Info = "IPv4 Address Class Type: \(ipsc!.netClass())\nIPv4 Address: \(ipsc!.ipv4Address)\nIPv4 Subnet ID: \(ipsc!.subnetId())\nIPv4 Subnet Mask: \(ipsc!.subnetMask())\nIPv4 Broadcast: \(ipsc!.subnetBroadcast())\nIPv4 Address Range: \(ipsc!.subnetRange())\nIPv4 Mask Bits: \(ipsc!.maskBits)\nIPv4 Subnet Bits: \(ipsc!.subnetBits())\nMax IPv4 Subnets: \(ipsc!.maxSubnets())\nIPv4 Max Hosts / Subnet: \(ipsc!.maxHosts())\nIPv4 Address Hexa: \(ipsc!.hexaMap())\nIPv4 Bit Map: \(ipsc!.bitMap())\nIPv4 Binary Map: \(ipsc!.binaryMap())\n" - let ipv6Info = "\nIPv6 Address: \(ipsc!.ipv6Address)\nLong IPv6 Address: \(ipsc!.fullAddressIPv6(ipAddress: ipsc!.ipv6Address))\nShort IPv6 Address: \(ipsc!.compactAddressIPv6(ipAddress: ipsc!.ipv6Address))\nIPv6-to-IPv4: \(IPSubnetCalc.convertIPv6toIPv4(ipAddress: ipsc!.ipv6Address))\nIPv6 Mask Bits: \(ipsc!.ipv6MaskBits)\nIPv6 Max Hosts / Subnet: \(ipsc!.totalIPAddrIPv6())\nNetwork: \(ipsc!.compactAddressIPv6(ipAddress: ipsc!.networkIPv6()))\nIPv6 Address Range: \(ipsc!.networkRangeIPv6())\nIPv6 Address Type: \(ipsc!.resBlockIPv6() ?? "None")\nIPv6 Address Hexa: \(ipsc!.hexaIDIPv6())\nIPv6 Address Dotted Decimal: \(ipsc!.dottedDecimalIPv6())\nIP6.ARPA: \(ipsc!.ip6ARPA())\n" + let ipv6Info = "\nIPv6 Address: \(ipsc!.ipv6Address)\nLong IPv6 Address: \(IPSubnetCalc.fullAddressIPv6(ipAddress: ipsc!.ipv6Address))\nShort IPv6 Address: \(IPSubnetCalc.compactAddressIPv6(ipAddress: ipsc!.ipv6Address))\nIPv6-to-IPv4: \(IPSubnetCalc.convertIPv6toIPv4(ipAddress: ipsc!.ipv6Address))\nIPv6 Mask Bits: \(ipsc!.ipv6MaskBits)\nIPv6 Max Hosts / Subnet: \(ipsc!.totalIPAddrIPv6())\nNetwork: \(IPSubnetCalc.compactAddressIPv6(ipAddress: ipsc!.networkIPv6()))\nIPv6 Address Range: \(ipsc!.networkRangeIPv6())\nIPv6 Address Type: \(ipsc!.resBlockIPv6() ?? "None")\nIPv6 Address Hexa: \(ipsc!.hexaIDIPv6())\nIPv6 Address Dotted Decimal: \(ipsc!.dottedDecimalIPv6())\nIP6.ARPA: \(ipsc!.ip6ARPA())\n" pb.setString(ipv4Info + ipv6Info, forType: NSPasteboard.PasteboardType.string) } } + /** + Enable or disable macOS Dark mode + + Triggered when the user selects Dark mode in the window menu. + + Auto triggered by macOS system based on the time of the day + + - Parameter sender: non used + + */ @IBAction func darkMode(_ sender: AnyObject) { if #available(OSX 10.14, *) { @@ -1265,16 +1601,25 @@ class SubnetCalcAppDelegate: NSObject, NSApplicationDelegate, NSWindowDelegate, } } + /** + Auto invoked when the Main Windows has been resized + */ func windowDidResize(_ notification: Notification) { bitsOnSlidePos() } + /** + Auto invoked when the Main Windows will be closed + */ func windowWillClose(_ notification: Notification) { NSApp.terminate(self) } + /** + Auto invoked when the application has finished launching + */ func applicationDidFinishLaunching(_ aNotification: Notification) { // Insert code here to initialize your application initSubnetsTab() @@ -1284,6 +1629,9 @@ class SubnetCalcAppDelegate: NSObject, NSApplicationDelegate, NSWindowDelegate, initVLSMTab() } + /** + Auto invoked when the application will be terminated + */ func applicationWillTerminate(_ aNotification: Notification) { // Insert code here to tear down your application } diff --git a/SubnetCalcUITests/SubnetCalcUITest.swift b/SubnetCalcUITests/SubnetCalcUITest.swift index f4a17bc..2507db5 100644 --- a/SubnetCalcUITests/SubnetCalcUITest.swift +++ b/SubnetCalcUITests/SubnetCalcUITest.swift @@ -193,6 +193,23 @@ class SubnetCalcUITest: XCTestCase { XCTAssertEqual(subnetcalcWindow.staticTexts["ipv6decimaltext"].value as! String, "32.1.13.184.0.0.133.163.0.0.0.0.172.31.128.1") XCTAssertEqual(subnetcalcWindow.staticTexts["ipv6arpatext"].value as! String, "1.0.0.8.f.1.c.a.0.0.0.0.0.0.0.0.3.a.5.8.0.0.0.0.8.b.d.0.1.0.0.2.ip6.arpa") + subnetcalcWindow.tabs["IPv6"].click() + ipaddrfieldTextField.click() + ipaddrfieldTextField.typeKey("a", modifierFlags:.command) + ipaddrfieldTextField.typeKey(.delete, modifierFlags:[]) + ipaddrfieldTextField.typeText("2a07:2900:8077:ffb1:e0::4/126\r") + XCTAssertEqual(subnetcalcWindow.staticTexts["ipv6addrtext"].value as! String, "2a07:2900:8077:ffb1:e0::4") + XCTAssertEqual(subnetcalcWindow.staticTexts["ipv4addrconvtext"].value as! String, "0.0.0.4") + XCTAssertEqual(subnetcalcWindow.comboBoxes["ipv6maskbitscombo"].value as! String, "126") + XCTAssertEqual(subnetcalcWindow.comboBoxes["ipv6maxsubnetscombo"].value as! String, "/126\t1 network") + XCTAssertEqual(subnetcalcWindow.comboBoxes["ipv6maxhostscombo"].value as! String, "4") + XCTAssertEqual(subnetcalcWindow.staticTexts["ipv6networktext"].value as! String, "2a07:2900:8077:ffb1:e0::4") + XCTAssertEqual(subnetcalcWindow.staticTexts["ipv6rangetext"].value as! String, "2a07:2900:8077:ffb1:00e0:0000:0000:0004 - 2a07:2900:8077:ffb1:00e0:0000:0000:0007") + XCTAssertEqual(subnetcalcWindow.staticTexts["ipv6typetext"].value as! String, "None") + XCTAssertEqual(subnetcalcWindow.staticTexts["ipv6hexatext"].value as! String, "0x2a0729008077ffb100e0000000000004") + XCTAssertEqual(subnetcalcWindow.staticTexts["ipv6decimaltext"].value as! String, "42.7.41.0.128.119.255.177.0.224.0.0.0.0.0.4") + XCTAssertEqual(subnetcalcWindow.staticTexts["ipv6arpatext"].value as! String, "4.0.0.0.0.0.0.0.0.0.0.0.0.e.0.0.1.b.f.f.7.7.0.8.0.0.9.2.7.0.a.2.ip6.arpa") + subnetcalcWindow.tabs["IPv6"].click() ipaddrfieldTextField.click() ipaddrfieldTextField.typeKey("a", modifierFlags:.command)