Last active
November 27, 2020 12:30
-
-
Save zapthedingbat/9a29c595d4ffa7ce41a0c68f45b21e10 to your computer and use it in GitHub Desktop.
Compression and decompression for Google's appallingly inefficient additional consent string
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
|| Compression and decompression using a combination of | |
|| Variable-length Quantity(VLQ) and Delta encoding to encode the "Additional | |
|| Consent" (AC) string required by Google’s Additional Consent Mode technical | |
|| specification https://support.google.com/admanager/answer/9681920?hl=en | |
|| | |
|| vendorIds.compress(input) | |
|| input - A string of "." delimited list if ids in ascending order. | |
|| | |
|| vendorIds.decompress(input) | |
|| input - The string created by a vendorIds.compress. | |
*/ | |
var vendorIds = (function () { | |
var byChar = {}; | |
var byOctet = {}; | |
Array.prototype.slice | |
.call("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=") | |
.forEach(function (a, c) { | |
(byChar[a] = c), (byOctet[c] = a); | |
}); | |
return { | |
compress: function (input) { | |
var ids = []; | |
var prev = 0; | |
return ( | |
input | |
.split(".") | |
.map(function (a) { | |
var b = parseInt(a, 10); | |
var c = b - prev; | |
prev = b; | |
return c; | |
}) | |
.forEach(function (a) { | |
do { | |
var b = 31 & a; | |
a >>>= 5; | |
if (0 < a) { | |
b |= 32; | |
} | |
ids.push(b); | |
} while (0 < a); | |
}), | |
ids | |
.map(function (a) { | |
return byOctet[a]; | |
}) | |
.join("") | |
); | |
}, | |
decompress: function (input) { | |
var octets = Array.prototype.slice.call(input).map(function (a) { | |
return byChar[a]; | |
}); | |
var ids = [], | |
shift = 0, | |
b = 0, | |
prev = 0; | |
for (var a, j = 0; j < octets.length; j += 1) { | |
a = octets[j]; | |
var flag = a & 32; | |
a &= 31; | |
b += a << shift; | |
if (flag) { | |
shift += 5; | |
} else { | |
// Delta decoding | |
var h = prev + b; | |
prev = h; | |
ids.push(h); | |
b = shift = 0; | |
} | |
} | |
return ids.join("."); | |
}, | |
}; | |
})(); | |
/* | |
|| Example usage | |
*/ | |
var testInput = | |
"39.43.46.55.61.66.70.83.89.93.108.117.122.124.131.135.136.143.144.147.149.159.162.167.171.184.192.196.202.211.218.228.230.239.241.253.259.266.272.286.291.311.317.322.323.326.327.338.367.371.385.389.393.394.397.407.413.415.424.430.436.440.445.448.449.453.482.486.491.494.495.501.503.505.522.523.540.550.559.560.568.571.574.576.584.585.587.588.591.733.737.745.780.787.802.803.817.820.821.829.839.853.864.867.874.899.904.922.931.938.979.981.985.1003.1024.1027.1031.1033.1034.1040.1046.1051.1053.1067.1085.1092.1095.1097.1099.1107.1126.1127.1135.1143.1149.1152.1162.1166.1171.1186.1188.1192.1201.1204.1205.1211.1215.1226.1227.1230.1248.1252.1268.1270.1276.1284.1286.1290.1301.1307.1312.1317.1329.1345.1356.1364.1365.1375.1403.1411.1415.1416.1419.1440.1442.1449.1455.1456.1465.1495.1512.1516.1525.1540.1548.1555.1558.1564.1570.1577.1579.1583.1584.1591.1603.1613.1616.1638.1651.1653.1665.1667.1671.1677.1678.1682.1697.1699.1703.1712.1716.1721.1722.1725.1732.1745.1750.1753.1765.1769.1782.1786.1800.1808.1810.1825.1827.1832.1837.1838.1840.1842.1843.1844.1845.1859.1866.1870.1878.1880.1889.1898.1899.1917.1929.1942.1944.1962.1963.1964.1967.1968.1969.1978.1998.2003.2007.2013.2027.2035.2039.2044.2047.2052.2056.2064.2068.2070.2072.2074.2088.2090.2103.2107.2109.2115.2124.2130.2133.2137.2140.2145.2147.2150.2156.2166.2177.2179.2183.2186.2202.2205.2213.2216.2219.2220.2222.2225.2234.2253.2264.2279.2282.2292.2299.2305.2309.2312.2316.2325.2328.2331.2334.2335.2336.2337.2343.2354.2357.2358.2359.2366.2370.2373.2376.2377.2387.2392.2394.2400.2403.2405.2406.2407.2411.2414.2416.2418.2425.2427.2440.2447.2459.2461.2462.2468.2472.2477.2481.2484.2486.2488.2492.2493.2496.2497.2498.2499.2504.2510.2511.2517.2526.2527.2531.2532.2534.2535.2542.2544.2552.2555.2563.2564.2567.2568.2569.2571.2572.2575.2577.2583.2584.2589.2595.2596.2601.2604.2605.2608.2609.2610.2612.2614.2621.2628.2629.2633.2634.2636.2642.2643.2645.2646.2647.2650.2651.2652.2656.2657.2658.2660.2661.2669.2670.2673.2677.2681.2682.2684.2686.2687.2690.2691.2695.2698.2707.2713.2714.2729.2739.2767.2768.2770.2771.2772.2784.2787.2791.2792.2797.2798.2801.2805.2812.2813.2816.2817.2818.2821.2822.2827.2830.2831.2834.2836.2838.2839.2840.2844.2846.2847.2849.2850.2851.2852.2854.2856.2860.2862.2863.2865.2867.2869.2873.2874.2875.2876.2878.2879.2880.2881.2882.2883.2884.2885.2886.2887.2888.2889.2891.2893.2894.2895.2897.2898.2900.2901.2908.2909.2911.2912.2913.2914.2916.2917.2918.2919.2920.2922.2923.2924.2927.2929.2930.2931.2933.2939.2940.2941.2942.2947.2949.2950.2956.2961.2962.2963.2964.2965.2966.2968.2969.2970.2973.2974.2975.2979.2980.2981.2983.2985.2986.2987.2991.2993.2994.2995.2997.3000.3002.3003.3005.3008.3009.3010.3011.3012.3016.3017.3018.3019.3024.3025.3033.3034.3037.3038.3043.3044.3045.3048.3050.3051.3052.3053.3055.3058.3059.3063.3065.3066.3068.3070.3072.3073.3074.3075.3076.3077.3078.3089.3090.3093.3094.3095.3097.3099.3100.3104.3106.3108.3109.3111.3112.3116.3117.3118.3119.3120.3121.3124.3126.3127.3128.3130.3135.3136.3139.3145.3149.3150.3151.3154.3155.3159.3162.3163.3165.3167.3172.3173.3180.3184.3185.3187.3188.3189.3190.3194.3196.3197"; | |
var testCompressed = vendorIds.compress(testInput); | |
var testResult = vendorIds.decompress(testCompressed); | |
console.log("Round Trip OK", testResult == testInput); | |
console.log("Input size", testInput.length); | |
console.log("Compressed size", testCompressed.length); | |
/* | |
|| Expected Output | |
*/ | |
/* | |
Round Trip OK true | |
Input size 3086 | |
Compressed size 646 | |
*/ |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
thanks to the bat!