1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
4 *
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8 *
9 * This file incorporates work covered by the following license notice:
10 *
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
18 */
19
20
21 #include "sunversion.hxx"
22 #include <osl/thread.h>
23 #include <rtl/character.hxx>
24 #include <string.h>
25 #if OSL_DEBUG_LEVEL >= 2
26 #include <osl/diagnose.h>
27 #include "diagnostics.h"
28 #endif
29 namespace jfw_plugin { //stoc_javadetect
30
31
32 #if OSL_DEBUG_LEVEL >= 2
33 class SelfTest
34 {
35 public:
36 SelfTest();
37 } test;
38 #endif
39
SunVersion(std::u16string_view usVer)40 SunVersion::SunVersion(std::u16string_view usVer):
41 m_nUpdateSpecial(0), m_preRelease(Rel_NONE)
42 {
43 OString sVersion= OUStringToOString(usVer, osl_getThreadTextEncoding());
44 m_bValid = init(sVersion.getStr());
45 }
SunVersion(const char * szVer)46 SunVersion::SunVersion(const char * szVer):
47 m_nUpdateSpecial(0), m_preRelease(Rel_NONE)
48 {
49 m_bValid = init(szVer);
50 }
51
52
53 /**Format major.minor.maintenance_update
54 */
init(const char * szVersion)55 bool SunVersion::init(const char *szVersion)
56 {
57 if (!szVersion || szVersion[0] == '\0')
58 return false;
59
60 //first get the major,minor,maintenance
61 const char * pLast = szVersion;
62 const char * pCur = szVersion;
63 //pEnd point to the position after the last character
64 const char * pEnd = szVersion + strlen(szVersion);
65 // 0 = major, 1 = minor, 2 = maintenance, 3 = update
66 int nPart = 0;
67 // position within part beginning with 0
68 int nPartPos = 0;
69 char buf[128];
70
71 //char must me a number 0 - 999 and no leading
72 while (true)
73 {
74 if (pCur < pEnd && rtl::isAsciiDigit(static_cast<unsigned char>(*pCur)))
75 {
76 pCur ++;
77 nPartPos ++;
78 }
79 //if correct separator then form integer
80 else if (
81 (nPartPos != 0) // prevents: ".4.1", "..1", part must start with digit
82 && (
83 //separators after maintenance (1.4.1_01, 1.4.1-beta, or 1.4.1)
84 (pCur == pEnd || *pCur == '_' || *pCur == '-')
85 ||
86 //separators between major-minor and minor-maintenance
87 (nPart < 2 && *pCur == '.') )
88 && (
89 //prevent 1.4.0. 1.4.0-
90 pCur + 1 != pEnd
91 || rtl::isAsciiDigit(static_cast<unsigned char>(*pCur))) )
92 {
93 bool afterMaint = pCur == pEnd || *pCur == '_' || *pCur == '-';
94
95 int len = pCur - pLast;
96 if (len >= 127)
97 return false;
98
99 strncpy(buf, pLast, len);
100 buf[len] = 0;
101 pCur ++;
102 pLast = pCur;
103
104 m_arVersionParts[nPart] = atoi(buf);
105
106 if (afterMaint)
107 nPart = 2;
108 nPart ++;
109 nPartPos = 0;
110 if (nPart == 3)
111 break;
112
113 //check next character
114 if (! ( (pCur < pEnd)
115 && ( (nPart < 3)
116 && rtl::isAsciiDigit(
117 static_cast<unsigned char>(*pCur)))))
118 return false;
119 }
120 else
121 {
122 return false;
123 }
124 }
125 if (pCur >= pEnd)
126 return true;
127 //We have now 1.4.1. This can be followed by _01, -beta, etc.
128 // _01 (update) According to docu must not be followed by any other
129 //characters, but on Solaris 9 we have a 1.4.1_01a!!
130 if (* (pCur - 1) == '_')
131 {// _01, _02
132 // update is the last part _01, _01a, part 0 is the digits parts and 1 the trailing alpha
133 while (true)
134 {
135 if (pCur <= pEnd)
136 {
137 if ( ! rtl::isAsciiDigit(static_cast<unsigned char>(*pCur)))
138 {
139 //1.8.0_102-, 1.8.0_01a,
140 size_t len = pCur - pLast;
141 if (len > sizeof(buf) - 1)
142 return false;
143 //we've got the update: 01, 02 etc
144 strncpy(buf, pLast, len);
145 buf[len] = 0;
146 m_arVersionParts[nPart] = atoi(buf);
147 if (pCur == pEnd)
148 {
149 break;
150 }
151 if (*pCur == 'a' && (pCur + 1) == pEnd)
152 {
153 //check if it s followed by a simple "a" (not specified)
154 m_nUpdateSpecial = *pCur;
155 break;
156 }
157 else if (*pCur == '-' && pCur < pEnd)
158 {
159 //check 1.5.0_01-ea
160 PreRelease pr = getPreRelease(++pCur);
161 if (pr == Rel_NONE)
162 return false;
163 //just ignore -ea because its no official release
164 break;
165 }
166 else
167 {
168 return false;
169 }
170 }
171 if (pCur < pEnd)
172 pCur ++;
173 else
174 break;
175 }
176 }
177 }
178 // 1.4.1-ea
179 else if (*(pCur - 1) == '-')
180 {
181 m_preRelease = getPreRelease(pCur);
182 if (m_preRelease == Rel_NONE)
183 return false;
184 #if defined(FREEBSD)
185 if (m_preRelease == Rel_FreeBSD)
186 {
187 pCur++; //eliminate 'p'
188 if (pCur < pEnd
189 && rtl::isAsciiDigit(static_cast<unsigned char>(*pCur)))
190 pCur ++;
191 int len = pCur - pLast -1; //eliminate 'p'
192 if (len >= 127)
193 return false;
194 strncpy(buf, (pLast+1), len); //eliminate 'p'
195 buf[len] = 0;
196 m_nUpdateSpecial = atoi(buf)+100; //hack for FBSD #i56953#
197 return true;
198 }
199 #endif
200 }
201 else
202 {
203 return false;
204 }
205 return true;
206 }
207
getPreRelease(const char * szRelease)208 SunVersion::PreRelease SunVersion::getPreRelease(const char *szRelease)
209 {
210 if (szRelease == nullptr)
211 return Rel_NONE;
212 if( ! strcmp(szRelease,"internal"))
213 return Rel_INTERNAL;
214 else if( ! strcmp(szRelease,"ea"))
215 return Rel_EA;
216 else if( ! strcmp(szRelease,"ea1"))
217 return Rel_EA1;
218 else if( ! strcmp(szRelease,"ea2"))
219 return Rel_EA2;
220 else if( ! strcmp(szRelease,"ea3"))
221 return Rel_EA3;
222 else if ( ! strcmp(szRelease,"beta"))
223 return Rel_BETA;
224 else if ( ! strcmp(szRelease,"beta1"))
225 return Rel_BETA1;
226 else if ( ! strcmp(szRelease,"beta2"))
227 return Rel_BETA2;
228 else if ( ! strcmp(szRelease,"beta3"))
229 return Rel_BETA3;
230 else if (! strcmp(szRelease, "rc"))
231 return Rel_RC;
232 else if (! strcmp(szRelease, "rc1"))
233 return Rel_RC1;
234 else if (! strcmp(szRelease, "rc2"))
235 return Rel_RC2;
236 else if (! strcmp(szRelease, "rc3"))
237 return Rel_RC3;
238 #if defined (FREEBSD)
239 else if (! strncmp(szRelease, "p", 1))
240 return Rel_FreeBSD;
241 #endif
242 else
243 return Rel_NONE;
244 }
245
~SunVersion()246 SunVersion::~SunVersion()
247 {
248
249 }
250
251 /* Examples:
252 a) 1.0 < 1.1
253 b) 1.0 < 1.0.0
254 c) 1.0 < 1.0_00
255
256 returns false if both values are equal
257 */
operator >(const SunVersion & ver) const258 bool SunVersion::operator > (const SunVersion& ver) const
259 {
260 if( &ver == this)
261 return false;
262
263 //compare major.minor.maintenance
264 for( int i= 0; i < 4; i ++)
265 {
266 // 1.4 > 1.3
267 if(m_arVersionParts[i] > ver.m_arVersionParts[i])
268 {
269 return true;
270 }
271 else if (m_arVersionParts[i] < ver.m_arVersionParts[i])
272 {
273 return false;
274 }
275 }
276 //major.minor.maintenance_update are equal. Test for a trailing char
277 if (m_nUpdateSpecial > ver.m_nUpdateSpecial)
278 {
279 return true;
280 }
281
282 //Until here the versions are equal
283 //compare pre -release values
284 if ((m_preRelease == Rel_NONE && ver.m_preRelease == Rel_NONE)
285 ||
286 (m_preRelease != Rel_NONE && ver.m_preRelease == Rel_NONE))
287 return false;
288 else if (m_preRelease == Rel_NONE && ver.m_preRelease != Rel_NONE)
289 return true;
290 else if (m_preRelease > ver.m_preRelease)
291 return true;
292
293 return false;
294 }
295
operator <(const SunVersion & ver) const296 bool SunVersion::operator < (const SunVersion& ver) const
297 {
298 return (! operator > (ver)) && (! operator == (ver));
299 }
300
operator ==(const SunVersion & ver) const301 bool SunVersion::operator == (const SunVersion& ver) const
302 {
303 bool bRet= true;
304 for(int i= 0; i < 4; i++)
305 {
306 if( m_arVersionParts[i] != ver.m_arVersionParts[i])
307 {
308 bRet= false;
309 break;
310 }
311 }
312 bRet = m_nUpdateSpecial == ver.m_nUpdateSpecial && bRet;
313 bRet = m_preRelease == ver.m_preRelease && bRet;
314 return bRet;
315 }
316
317
318 #if OSL_DEBUG_LEVEL >= 2
SelfTest()319 SelfTest::SelfTest()
320 {
321 bool bRet = true;
322
323 static char const * versions[] = {"1.4.0", "1.4.1", "1.0.0", "10.0.0", "10.10.0",
324 "10.2.2", "10.10.0", "10.10.10", "111.0.999",
325 "1.4.1_01", "9.90.99_09", "1.4.1_99",
326 "1.4.1_00a",
327 "1.4.1-ea", "1.4.1-beta", "1.4.1-rc1",
328 "1.5.0_01-ea", "1.5.0_01-rc2"};
329 static char const * badVersions[] = {".4.0", "..1", "", "10.0", "10.10.0.", "10.10.0-", "10.10.0.",
330 "10.2-2", "10_10.0", "10..10","10.10", "a.0.999",
331 "1.4b.1_01", "9.90.-99_09", "1.4.1_99-",
332 "1.4.1_00a2", "1.4.0_z01z", "1.4.1__99A",
333 "1.4.1-1ea", "1.5.0_010", "1.5.0._01-", "1.5.0_01-eac"};
334 static char const * orderedVer[] = { "1.3.1-ea", "1.3.1-beta", "1.3.1-rc1",
335 "1.3.1", "1.3.1_00a", "1.3.1_01", "1.3.1_01a",
336 "1.3.2", "1.4.0", "1.5.0_01-ea", "2.0.0"};
337
338 int num = SAL_N_ELEMENTS (versions);
339 int numBad = SAL_N_ELEMENTS (badVersions);
340 int numOrdered = SAL_N_ELEMENTS (orderedVer);
341 //parsing test (positive)
342 for (int i = 0; i < num; i++)
343 {
344 SunVersion ver(versions[i]);
345 if ( ! ver)
346 {
347 bRet = false;
348 break;
349 }
350 }
351 OSL_ENSURE(bRet, "SunVersion selftest failed");
352 //Parsing test (negative)
353 for ( int i = 0; i < numBad; i++)
354 {
355 SunVersion ver(badVersions[i]);
356 if (ver)
357 {
358 bRet = false;
359 break;
360 }
361 }
362 OSL_ENSURE(bRet, "SunVersion selftest failed");
363
364 // Ordering test
365 bRet = true;
366 int j = 0;
367 for (int i = 0; i < numOrdered; i ++)
368 {
369 SunVersion curVer(orderedVer[i]);
370 if ( ! curVer)
371 {
372 bRet = false;
373 break;
374 }
375 for (j = 0; j < numOrdered; j++)
376 {
377 SunVersion compVer(orderedVer[j]);
378 if (i < j)
379 {
380 if ( !(curVer < compVer))
381 {
382 bRet = false;
383 break;
384 }
385 }
386 else if ( i == j)
387 {
388 if (! (curVer == compVer
389 && ! (curVer > compVer)
390 && ! (curVer < compVer)))
391 {
392 bRet = false;
393 break;
394 }
395 }
396 else if (i > j)
397 {
398 if ( !(curVer > compVer))
399 {
400 bRet = false;
401 break;
402 }
403 }
404 }
405 if ( ! bRet)
406 break;
407 }
408 if (bRet)
409 JFW_TRACE2("Testing class SunVersion succeeded.");
410 else
411 OSL_ENSURE(bRet, "[Java framework] sunjavaplugin: SunVersion self test failed.");
412 }
413 #endif
414
415 }
416
417 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
418