Files
opennurbs/opennurbs_version_number.cpp
Bozo The Builder f26b1ba26a Sync changes from upstream repository
First publish of public opennurbs from 8.x source
2022-07-28 11:12:21 -07:00

668 lines
16 KiB
C++

#include "opennurbs.h"
#if !defined(ON_COMPILING_OPENNURBS)
// This check is included in all opennurbs source .c and .cpp files to insure
// ON_COMPILING_OPENNURBS is defined when opennurbs source is compiled.
// When opennurbs source is being compiled, ON_COMPILING_OPENNURBS is defined
// and the opennurbs .h files alter what is declared and how it is declared.
#error ON_COMPILING_OPENNURBS must be defined when compiling opennurbs
#endif
#define BRANCH_MAX 0x03
#define TIME_MAX 0x0FFFF
static
unsigned int ON_VersionNumberTime(
unsigned int year,
unsigned int month,
unsigned int day_of_month
)
{
unsigned int time;
unsigned int day_of_year;
day_of_year = (year < 2100 && year >= 2000)
? ON_DayOfGregorianYear(year,month,day_of_month)
: 0;
if ( day_of_year > 0 )
{
time = (year - 2000)*367 + day_of_year;
}
else
{
time = 0;
}
return time;
}
static
bool ON_VersionNumberTimeDeconstruct(
unsigned int time,
unsigned int* time_year,
unsigned int* time_month,
unsigned int* time_day_of_month
)
{
unsigned int year = 0;
unsigned int month = 0;
unsigned int day_of_month = 0;
unsigned int u = time;
if (u > 0)
{
unsigned int day_of_year = (u%367);
u /= 367;
if (day_of_year > 0 && u < 100)
{
year = u + 2000;
if ( !ON_GetGregorianMonthAndDayOfMonth(year,day_of_year,&month,&day_of_month) )
{
year = 0;
month = 0;
day_of_month = 0;
}
}
}
if ( 0!= time_year)
*time_year = year;
if ( 0!= time_month)
*time_month = month;
if ( 0!= time_day_of_month)
*time_day_of_month = day_of_month;
return (0 != month);
}
unsigned int ON_VersionNumberConstruct(
unsigned int major_version,
unsigned int minor_version,
unsigned int year,
unsigned int month,
unsigned int day_of_month,
unsigned int platform_branch
)
{
unsigned int version_number = 0;
unsigned int version_time = ON_VersionNumberTime(year,month,day_of_month);
if (version_time > TIME_MAX)
version_time = TIME_MAX;
// platform
// 0 = developer
// 1 = Windows Commercial/Beta/WIP
// 2 = Mac OS Commercial/Beta/WIP
unsigned int platform
= (platform_branch > 0)
? (2 - (platform_branch % 2) )
: 0;
if ( platform > BRANCH_MAX )
platform = 0; // all invalid branch numbers get mapped to "developer"
if ( minor_version > ON::VersionMinorMaximum())
minor_version = ON::VersionMinorMaximum();
if ( major_version > ON::VersionMajorMaximum())
major_version = ON::VersionMajorMaximum();
version_number = ((major_version*(ON::VersionMinorMaximum()+1) + minor_version)*(TIME_MAX+1) + version_time)*(BRANCH_MAX+1) + platform;
version_number |= 0x80000000;
return version_number;
}
unsigned int ON_VersionNumberFromYearMonthDateFormat(
unsigned int version_number_major,
unsigned int YYYYMMDDn_version_number
)
{
unsigned int version_number = 0;
if ( ON_VersionNumberIsYearMonthDateFormat(version_number_major,YYYYMMDDn_version_number) )
{
// convert old format to new format
unsigned int n = (YYYYMMDDn_version_number % 10);
unsigned int day_of_month = (YYYYMMDDn_version_number/10) % 100;
unsigned int month = (YYYYMMDDn_version_number/1000) % 100;
unsigned int year = (YYYYMMDDn_version_number/100000);
unsigned int major_version = (version_number_major > 0 )
? version_number_major
: ((n > 0 && n < 9) ? n : 5);
unsigned int minor_version = 0;
unsigned int branch = 0; // 0 = developer
version_number = ON_VersionNumberConstruct(
major_version,
minor_version,
year,
month,
day_of_month,
branch
);
}
return version_number;
}
unsigned int ON_VersionNumberMinimum(unsigned int major_version)
{
unsigned int version_number_minimum = ON_VersionNumberConstruct(
major_version,0,
2000,1,1,
0
);
return version_number_minimum;
}
bool ON_VersionNumberIsYearMonthDateFormat(
unsigned int archive_3dm_version,
unsigned int version_number
)
{
// Note:
// When new versions of opennurbs save V2,V3,V4 or V5 files,
// they have to write old yyyymmddn verison numbers so the
// old code will read the file. In this case, n = 6,7,8,9.
// (n=9 meant debug prior to 2014);
//
// 200012210 is the earliest known opennurbs version number
bool rc = false;
unsigned int min_old_format_year = 2000;
unsigned int max_old_format_year = 2100;
if ( version_number >= min_old_format_year*100000 + 1010
&& version_number < max_old_format_year*100000
)
{
unsigned int day_of_month = (version_number/10) % 100;
unsigned int month = (version_number/1000) % 100;
unsigned int year = (version_number/100000);
if ( year >= min_old_format_year
&& year < max_old_format_year
&& month >= 1 && month <= 12
&& day_of_month >= 1 && day_of_month <= ON_DaysInMonthOfGregorianYear(year,month)
)
{
unsigned int version_major = (archive_3dm_version >= 50 && 0 == (archive_3dm_version%10)) ? (archive_3dm_version/10) : archive_3dm_version;
// valid yyyy-mm-dd - check n
unsigned int n = version_number%10;
if (0 == n && 200612060 == version_number)
n = 5; // bug in 32-bit Rhino 5 SR12 SDK version number (2006 is also a bogus year for V5!)
else if ( 9 == n && year <= 2016 )
{
// 9 was used by debug builds in V2, V3, V4 and V5.
n = version_major;
}
if ( (0 != n && n == version_major)
|| (n <= 4 && year <= 2011)
|| (5==n && year >= 2006)
|| (6==n && year >= 2012)
|| (n>=7 && year >= 2018)
)
{
rc = true;
}
}
}
return rc;
}
bool ON_VersionNumberIsValid(
unsigned int version_number
)
{
bool rc = ( version_number >= ON_VersionNumberMinimum(1) );
if (rc)
{
unsigned int version_major = 0;
unsigned int version_minor = 0;
unsigned int version_branch = 0;
unsigned int version_year = 0;
unsigned int version_month = 0;
unsigned int version_day_of_month = 0;
rc = ON_VersionNumberParse(
version_number,
&version_major,
&version_minor,
&version_year,
&version_month,
&version_day_of_month,
&version_branch
);
if (rc)
{
const unsigned int v = ON_VersionNumberConstruct(version_major,version_minor,version_year,version_month,version_day_of_month,version_branch);
if ( v != version_number )
rc = false;
}
}
return rc;
}
bool ON_VersionNumberParse(
unsigned int version_number,
unsigned int* version_major,
unsigned int* version_minor,
unsigned int* version_year,
unsigned int* version_month,
unsigned int* version_day_of_month,
unsigned int* version_branch
)
{
unsigned int u;
unsigned int version_time;
unsigned int max;
bool rc;
u = version_number;
if ( ON_VersionNumberIsYearMonthDateFormat(0,u) )
{
unsigned int n = u%10;
u /= 10;
unsigned int dd = u % 100;
u /= 100;
unsigned int mm = u %100;
u /= 100;
if (0 == n && 200612060 == version_number)
n = 5; // 32-bit Rhino V5 SR12 version number bug
else if (0 == n)
n = 2;
else if ( 9 == n && u < 2017 )
n = 5; // debug maps to 5
u = ON_VersionNumberConstruct(n,0,u,mm,dd,0);
}
if ( 0 == (0x80000000 & u) )
{
// This number was not created by ON_VersionNumberConstruct()
u = 0;
}
else
{
// Clear the bit that makes new version numbers
// created ON_VersionNumberConstruct()
// bigger than old yyyymmddn version numbers.
u &= 0x7FFFFFFF;
}
max = BRANCH_MAX+1;
if ( 0 != version_branch )
*version_branch = u % max;
u /= max;
max = TIME_MAX+1;
version_time = u % max;
u /= max;
rc = ON_VersionNumberTimeDeconstruct(
version_time,
version_year,
version_month,
version_day_of_month);
max = ON::VersionMinorMaximum()+1;
if ( 0 != version_minor )
*version_minor = u % max;
u /= max;
if ( 0 != version_major )
*version_major = u;
return rc;
}
const ON_String ON_VersionNumberToString(
unsigned int version_number,
bool bUnsignedFormat,
bool bDateFormat
)
{
unsigned int version_major = 0;
unsigned int version_minor = 0;
unsigned int version_year = 0;
unsigned int version_month = 0;
unsigned int version_day_of_month = 0;
unsigned int version_branch = 0;
if (false == ON_VersionNumberIsValid(version_number))
{
bUnsignedFormat = false;
bDateFormat = false;
}
else if (bDateFormat)
{
bDateFormat = ON_VersionNumberParse(
version_number,
&version_major,
&version_minor,
&version_year,
&version_month,
&version_day_of_month,
&version_branch
);
}
ON_String str_version;
if (bUnsignedFormat)
{
str_version = ON_String::FormatToString("%u", version_number);
if (bDateFormat)
str_version += " (";
}
if (bDateFormat)
{
str_version += ON_String::FormatToString(
"%u.%u %04u-%02u-%02u:%u",
version_major,
version_minor,
version_year,
version_month,
version_day_of_month,
version_branch
);
if (bUnsignedFormat)
str_version += ")";
}
if (str_version.IsEmpty())
{
str_version =
(0 != version_number)
? ON_String::FormatToString("0x%08X", version_number)
: "0";
}
return str_version;
}
const ON_wString ON_VersionNumberToWideString(
unsigned int version_number,
bool bUnsignedFormat,
bool bDateFormat
)
{
return ON_wString(ON_VersionNumberToString(version_number, bUnsignedFormat, bDateFormat));
}
const ON_String ON_SdkVersionNumberToString(
unsigned int sdk_version_number,
unsigned int sdk_service_release_number
)
{
const bool bValidVersionNumber = ON_VersionNumberIsValid(sdk_version_number);
const bool bValidServiceReleaseNumber = ON_VersionNumberIsValid(sdk_service_release_number);
ON_String str_version = ON_VersionNumberToString(sdk_version_number, true, false);
str_version += ".";
str_version += ON_VersionNumberToString(sdk_service_release_number, true, false);
if (bValidVersionNumber || bValidServiceReleaseNumber)
{
str_version += " (";
if (bValidVersionNumber != bValidServiceReleaseNumber || sdk_version_number == sdk_service_release_number )
{
str_version += ON_VersionNumberToString(bValidVersionNumber ? sdk_version_number : sdk_service_release_number, false, true);
}
else
{
str_version += ON_VersionNumberToString(sdk_version_number, false, true);
str_version += ", ";
str_version += ON_VersionNumberToString(sdk_service_release_number, false, true);
}
str_version += ")";
}
return str_version;
}
const ON_wString ON_SdkVersionNumberToWideString(
unsigned int sdk_version_number,
unsigned int sdk_service_release_number
)
{
return ON_wString(ON_SdkVersionNumberToString(sdk_version_number, sdk_service_release_number));
}
static
unsigned int AppendValueToString(
unsigned int u,
size_t string_buffer_capacity,
char* string_buffer
)
{
unsigned int digit_count = 0;
unsigned int i;
if ( string_buffer_capacity > 0 && 0 != string_buffer )
{
i = u;
for(;;)
{
digit_count++;
i /= 10;
if ( i < 1 )
break;
}
if ( digit_count >= string_buffer_capacity )
digit_count = 0;
else
{
i = digit_count;
string_buffer[i] = 0;
for (;;)
{
i--;
string_buffer[i] = (u % 10) + '0';
u /= 10;
if ( u < 1 )
break;
}
}
}
return digit_count;
}
unsigned int ON_GetVersionQuartet(
unsigned int major_version,
unsigned int minor_version,
unsigned int year,
unsigned int month,
unsigned int day_of_month,
unsigned int hour,
unsigned int minute,
unsigned int branch,
unsigned short quartet_values[4]
)
{
unsigned int i;
unsigned int item_value;
unsigned int version_number = ON_VersionNumberConstruct(
major_version,
minor_version,
year,
month,
day_of_month,
branch
);
if ( hour >= 24 || minute >= 60 )
{
if ( 24 == hour && 0 == minute )
{
// leap second
hour = 23;
minute = 60;
}
if ( 23 != hour || 60 != minute )
{
hour = 0;
minute = 0;
}
}
for(i = 0; i < 4; i++ )
{
switch(i)
{
case 0:
item_value = major_version;
break;
case 1:
item_value = minor_version;
break;
case 2:
item_value = (year-2000)*1000 + ON_DayOfGregorianYear(year,month,day_of_month);
break;
case 3:
item_value = (hour*100 + minute)*10 + branch;
break;
default:
continue;
break;
}
if ( item_value > 0xFFFF )
{
version_number = 0;
item_value = 0;
}
quartet_values[i] = (unsigned short)item_value;
}
return version_number;
}
unsigned int ON_GetVersionString(
unsigned int major_version,
unsigned int minor_version,
unsigned int year,
unsigned int month,
unsigned int day_of_month,
unsigned int hour,
unsigned int minute,
unsigned int branch,
size_t string_buffer_capacity,
char* string_buffer
)
{
char s[24] = {0};
const size_t s_capacity = sizeof(s)/sizeof(s[0]);
unsigned int string_length = 0;
unsigned int i, j;
unsigned short quartet_values[4] = {0};
unsigned int version_number = ON_GetVersionQuartet(
major_version,
minor_version,
year,
month,
day_of_month,
hour,
minute,
branch,
quartet_values
);
if (string_buffer_capacity <= 0 || nullptr == string_buffer)
{
string_buffer_capacity = s_capacity;
string_buffer = s;
}
if ( version_number > 0 )
{
for(i = 0; i < 4 && string_length < string_buffer_capacity; i++ )
{
if ( i > 0 )
string_buffer[string_length++] = '.';
j = AppendValueToString(
quartet_values[i],
string_buffer_capacity - string_length,
string_buffer + string_length
);
if ( j <= 0 )
{
string_length = 0;
break;
}
string_length += j;
}
}
if ( string_length > string_buffer_capacity )
string_length = 0;
for ( i = string_length; i < string_buffer_capacity; i++ )
string_buffer[i] = 0;
return string_length;
}
unsigned int ON_GetVersionWideString(
unsigned int major_version,
unsigned int minor_version,
unsigned int year,
unsigned int month,
unsigned int day_of_month,
unsigned int hour,
unsigned int minute,
unsigned int branch,
size_t string_buffer_capacity,
wchar_t* string_buffer
)
{
char s[24] = {0};
const size_t s_capacity = sizeof(s)/sizeof(s[0]);
unsigned int string_length;
unsigned int i;
string_length = ON_GetVersionString(
major_version,
minor_version,
year,
month,
day_of_month,
hour,
minute,
branch,
s_capacity, s
);
if (string_buffer_capacity > 0 && nullptr != string_buffer)
{
if (((size_t)string_length) <= string_buffer_capacity)
{
for (i = 0; i < string_length && 0 != s[i]; i++)
{
string_buffer[i] = s[i];
}
}
else
{
string_length = 0;
i = 0;
}
while (i < string_buffer_capacity)
string_buffer[i++] = 0;
}
return string_length;
}