Alpha-encoding file versions
When building installers the UpgradeVersion
must have a unique property value that is an installer public property (upper-case alpha). So, what better way of adding uniqueness than making it have the form "product name + product version" with the version suitably encoded...
So, a script for turning a file version (4 x 16bit ints) encoded as a System.Version
into a short alpha string, assuming that Major and Minor will be small, and that common approaches are to step Build, to use a stepped Build plus date-stamped Revision, or a timestamp Build and Revision --
from System import Version | |
def encode13(value, flag): | |
v = value + (13 if flag else 0) | |
return chr(ord('A')+v) | |
def encode25(value): | |
return chr(ord('A')+value) | |
def encodePrimary(value): | |
def encodePrimaryHelper(value, result): | |
digit = value % 13 | |
rest = value /13 | |
result += encode13(digit, rest) | |
if rest: | |
return encodePrimaryHelper(rest, result) | |
else: | |
return result | |
return encodePrimaryHelper(value, '') | |
def encodeByte(value): | |
if 0 == value: | |
return 'Z' | |
else: | |
return encode25(value/25)+encode25(value%25) | |
def encodeWord(value): | |
bottom = value % 256 | |
top = (value/256) % 256 | |
return encodeByte(top)+encodeByte(bottom) | |
def encodeVersion(version): | |
value = (encodePrimary(version.Major) + | |
encodePrimary(version.Minor) + | |
encodeWord(version.Build)) | |
if version.Revision: | |
value += encodeWord(version.Revision) | |
return value | |
if __name__ == '__main__': | |
import unittest | |
class TestEncode(unittest.TestCase): | |
def testPrimary(self): | |
self.assertEqual(encodePrimary(0), 'A', 'encode 0') | |
self.assertEqual(encodePrimary(11), 'L', 'encode 11') | |
self.assertEqual(encodePrimary(13), 'NB', 'encode 13') | |
self.assertEqual(encodePrimary(32), 'TC', 'encode 32') | |
self.assertEqual(encodePrimary(169), 'NNB', 'encode 13') | |
def testByte(self): | |
self.assertEqual(encodeByte(0), 'Z', 'encode 0') | |
self.assertEqual(encodeByte(1), 'AB', 'encode 1') | |
self.assertEqual(encodeByte(25), 'BA', 'encode 25') | |
self.assertEqual(encodeByte(255), 'KF', 'encode 255') | |
def testVersion(self): | |
self.assertEqual(encodeVersion(Version('1.0.0.0')), | |
'BAZZ', 'encode 1.0.0.0') | |
self.assertEqual(encodeVersion(Version('1.0.0.1')), | |
'BAZZZAB', 'encode 1.0.0.1') | |
self.assertEqual(encodeVersion(Version('1.0.33.0')), | |
'BAZBI', 'encode 1.0.33.0') | |
self.assertEqual(encodeVersion(Version('1.0.3369.23350')), | |
'BAANBQDQCE', '1.0.3369.23350') | |
unittest.main() |
where the first two facets are encoded as telescoped base-13 (with a bit to say "more to come"), and the second two are encoded as pairs of bytes -- Z for a zero byte or as a 2-character base-25 representation if non-zero, with a zero Revision being dropped. This gives 10 characters in a plausible worst case, or as low as 5 in some conventions (stepped build numbers only); as opposed to the naive 64-bit as all-base-26 which would give 11 characters always.
No comments :
Post a Comment