问题
I've posted a function that will convert an IPv6 address to a 128-bit unsigned int value here: ColdFusion IPv6 to 128-bit unsigned int
I need a function that will go in the other direction now.
This function turned out to be more complicated and I'll explain the complications in the answer.
回答1:
Here is the function that will convert a 128-bit unsigned int to an IPv6 address with the correct (concise) IPv6 formatting.
Explanations: Part of the problem with a function like this is that the number passed into the function (nUInt128) is not guaranteed to be a 128-bit unsigned int. It might be 8-bits (::1) or even weird stuff like a signed 136-bit number (ColdFusion/Java seems to prefer signed ints). Not having exactly a 128-bit number that gets converted to a Java Byte array with 16 values will cause java.net.Inet6Address.getAddress() to throw an error. My solution was to create a ColdFusion array with 16 zeros and back-fill it and then use that with java.net.Inet6Address.getAddress(). I was surprised that this worked as I have no idea how large the numbers are in that array. ColdFusion/Java somehow did some magic and turned the array into a Byte[]. The back-fill also strips off the numbers that are larger and fixes the 136-bit signed int problem.
<cffunction name="UInt128ToIPv6" returntype="string" output="no" access="public" hint="returns IPv6 address for uint128 number">
<cfargument name="nUInt128" type="numeric" required="yes" hint="uint128 to convert to ipv6 address">
<cfif arguments.nUInt128 EQ 0>
<cfreturn "">
</cfif>
<cftry>
<cfset local['javaMathBigInteger'] = CreateObject("java", "java.math.BigInteger").init(arguments.nUInt128)>
<cfset local['JavaNetInet6Address'] = CreateObject("java", "java.net.Inet6Address")>
<cfset local['arrBytes'] = local.javaMathBigInteger.toByteArray()>
<!--- correct the array length if !=16 bytes --->
<cfset local['arrFixedBytes'] = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]>
<cfif arrayLen(local.arrBytes) NEQ 16>
<cfset local['nFixedIndex'] = 16>
<cfset local['nBytesIndex'] = arrayLen(local.arrBytes)>
<cfloop condition="local.nFixedIndex NEQ 0 && local.nBytesIndex NEQ 0">
<cfset local.arrFixedBytes[local.nFixedIndex] = local.arrBytes[local.nBytesIndex]>
<cfset local.nFixedIndex-->
<cfset local.nBytesIndex-->
</cfloop>
</cfif>
<!--- /correct the array length if !=16 bytes --->
<cfif arrayLen(local.arrBytes) NEQ 16>
<cfset local['vcIPv6'] = local.JavaNetInet6Address.getByAddress(local.arrFixedBytes).getHostAddress()>
<cfelse>
<cfset local['vcIPv6'] = local.JavaNetInet6Address.getByAddress(local.javaMathBigInteger.toByteArray()).getHostAddress()>
</cfif>
<cfcatch type="any">
<cfset local['vcIPv6'] = "">
</cfcatch>
</cftry>
<cfreturn formatIPv6(vcIPv6 = local.vcIPv6)>
</cffunction>
Here is the formatIPv6() utility function that is called at the end of the previous function.
<cffunction name="formatIPv6" returntype="string" output="yes" access="public" hint="returns a compressed ipv6 address">
<cfargument name="vcIPv6" type="string" required="yes" hint="IPv6 address">
<!--- inside reReplace removes leading zeros, outside reReplace removes repeating ":" and "0:" --->
<cfreturn reReplace(reReplace(LCase(arguments.vcIPv6), "(:|^)(0{0,3})([1-9a-f]*)", "\1\3", "all"), "(^|:)[0|:]+:", "::", "all")>
</cffunction>
If you have any suggestions/questions, please leave comments.
来源:https://stackoverflow.com/questions/43203963/coldfusion-128-bit-unsigned-int-to-ipv6