Branch data Line data Source code
1 : : /*
2 : : * SPDX-License-Identifier: MIT
3 : : * Copyright (c) 2024 IUPAC and InChI Trust
4 : : */
5 : :
6 : : #include <stdlib.h>
7 : : #include <string.h>
8 : :
9 : : #include "mode.h"
10 : : #include "ichimain.h"
11 : : #include "ichi_io.h"
12 : :
13 : : #include "bcf_s.h"
14 : : #include "stb_sprintf.h"
15 : :
16 : : #include "logging.h" /*(@nnuk : Nauman Ullah Khan) :: Needed for logging functionality*/
17 : :
18 : : /* Local */
19 : :
20 : : int GetHillFormulaCounts( U_CHAR *nAtom,
21 : : S_CHAR *nNum_H,
22 : : int num_atoms,
23 : : AT_NUMB *nTautomer,
24 : : int lenTautomer,
25 : : int *pnum_C,
26 : : int *pnum_H,
27 : : int *pnLen,
28 : : int *pnNumNonHAtoms );
29 : : int MakeHillFormula( U_CHAR *nAtom,
30 : : int num_atoms,
31 : : char *szLinearCT,
32 : : int nLen_szLinearCT,
33 : : int num_C,
34 : : int num_H,
35 : : int *bOverflow );
36 : :
37 : : #if ( FIX_DALKE_BUGS == 1 )
38 : : #else
39 : : char *AllocateAndFillHillFormula( INChI *pINChI );
40 : : #endif
41 : :
42 : : int AddElementAndCount( const char *szElement,
43 : : int mult, char *szLinearCT,
44 : : int nLenLinearCT,
45 : : int *bOverflow );
46 : :
47 : : int Copy2StereoBondOrAllene( INChI_Stereo *Stereo,
48 : : int *nNumberOfStereoCenters,
49 : : int *nNumberOfStereoBonds,
50 : : AT_STEREO_DBLE *LinearCTStereoDble,
51 : : AT_NUMB *pCanonOrd, AT_RANK *pCanonRank,
52 : : sp_ATOM *at,
53 : : int bIsotopic );
54 : :
55 : : int CopyLinearCTStereoToINChIStereo( INChI_Stereo *Stereo,
56 : : AT_STEREO_CARB *LinearCTStereoCarb,
57 : : int nLenLinearCTStereoCarb,
58 : : AT_STEREO_DBLE *LinearCTStereoDble,
59 : : int nLenLinearCTStereoDble,
60 : : AT_NUMB *pCanonOrd, AT_RANK *pCanonRank,
61 : : sp_ATOM *at,
62 : : int bIsotopic,
63 : : AT_STEREO_CARB *LinearCTStereoCarbInv,
64 : : AT_STEREO_DBLE *LinearCTStereoDbleInv,
65 : : AT_NUMB *pCanonOrdInv,
66 : : AT_RANK *pCanonRankInv );
67 : :
68 : : int GetHillFormulaIndexLength( int count );
69 : :
70 : : int MarkAmbiguousStereo( sp_ATOM *at,
71 : : inp_ATOM *norm_at,
72 : : int bIsotopic,
73 : : AT_NUMB *pCanonOrd,
74 : : AT_STEREO_CARB *LinearCTStereoCarb, int nLenLinearCTStereoCarb,
75 : : AT_STEREO_DBLE *LinearCTStereoDble, int nLenLinearCTStereoDble );
76 : :
77 : : INCHI_MODE UnmarkAllUndefinedUnknownStereo( INChI_Stereo *Stereo, INCHI_MODE nUserMode );
78 : :
79 : : int CleanCoord( MOL_COORD szCoord, int delim );
80 : :
81 : :
82 : :
83 : : /****************************************************************************
84 : : Print single-component Hill formula whole structure output.
85 : : ****************************************************************************/
86 : 146 : int MakeHillFormulaString( char *szHillFormula,
87 : : INCHI_IOS_STRING *strbuf,
88 : : int *bOverflow )
89 : : {
90 : 146 : int nUsedLength0 = strbuf->nUsedLength;
91 [ + - + - ]: 146 : if (szHillFormula && !*bOverflow)
92 : : {
93 [ - + ]: 146 : if (-1 == inchi_strbuf_printf( strbuf, "%s", szHillFormula ))
94 : : {
95 : 0 : *bOverflow |= 1;
96 : 0 : return nUsedLength0 + 1;
97 : : }
98 : : }
99 : 146 : return ( strbuf->nUsedLength - nUsedLength0 );
100 : : }
101 : :
102 : :
103 : : /****************************************************************************
104 : : MS Windows dependent: sprintf() is supposed to return the length
105 : : of the output string.
106 : : Carbon atoms are always first.
107 : : Bridging hydrogen atoms are always last.
108 : : ****************************************************************************/
109 : 367 : int GetHillFormulaIndexLength( int count )
110 : : {
111 : : char szCount[16];
112 [ + + ]: 367 : if (count > 1)
113 : : {
114 : 198 : return sprintf(szCount, "%d", count);
115 : : }
116 : :
117 : 169 : return 0;
118 : : }
119 : :
120 : :
121 : : /****************************************************************************
122 : : Estimate dimensions of Hill formula for single component
123 : : ****************************************************************************/
124 : 161 : int GetHillFormulaCounts( U_CHAR *nAtom,
125 : : S_CHAR *nNum_H,
126 : : int num_atoms,
127 : : AT_NUMB *nTautomer,
128 : : int lenTautomer,
129 : : int *pnum_C,
130 : : int *pnum_H,
131 : : int *pnLen,
132 : : int *pnNumNonHAtoms )
133 : : {
134 : : char szElement[4];
135 : 161 : U_CHAR nPrevAtom = (U_CHAR) -2;
136 : : int bCarbon, bHydrogen, nElemLen, nFormLen, nNumNonHAtoms;
137 : : int mult, i, num_H, num_C;
138 : :
139 : 161 : num_H = 0;
140 : 161 : num_C = 0;
141 : 161 : bCarbon = 0;
142 : 161 : bHydrogen = 0;
143 : 161 : nElemLen = 0;
144 : 161 : nFormLen = 0;
145 : 161 : mult = 0;
146 : 161 : nNumNonHAtoms = num_atoms;
147 : :
148 [ + + ]: 971 : for (i = 0; i < num_atoms; i++)
149 : : {
150 [ + + ]: 810 : if (nPrevAtom != nAtom[i])
151 : : {
152 [ + + ]: 272 : if (mult)
153 : : {
154 [ - + ]: 111 : if (bHydrogen)
155 : : {
156 : 0 : num_H += mult;
157 : : }
158 [ + + ]: 111 : else if (bCarbon)
159 : : {
160 : 62 : num_C += mult;
161 : : }
162 : : else
163 : : {
164 : 49 : nFormLen += nElemLen;
165 : 49 : nFormLen += GetHillFormulaIndexLength( mult );
166 : : }
167 : : }
168 : : /*if (-1 == get_element_chemical_symbol( (int) nAtom[i], szElement ))*/
169 [ - + ]: 272 : if (-1 == get_element_or_pseudoelement_symbol( (int) nAtom[i], szElement ))
170 : : {
171 : 0 : return -1;
172 : : }
173 : 272 : mult = 1;
174 : 272 : nElemLen = (int) strlen( szElement );
175 : 272 : nPrevAtom = nAtom[i];
176 : 272 : bCarbon = !strcmp( szElement, "C" );
177 : 272 : bHydrogen = !strcmp( szElement, "H" );
178 [ + + ]: 272 : if (bHydrogen)
179 : : {
180 : 6 : nNumNonHAtoms = i;
181 : : }
182 : : }
183 : : else
184 : : {
185 : 538 : mult++;
186 : : }
187 : :
188 : 810 : num_H += nNum_H[i];
189 : : }
190 : :
191 : : /* NumGroups; ((NumAt+1, NumH, At1..AtNumAt),...) */
192 : :
193 [ + - + + ]: 161 : if (nTautomer && lenTautomer > 0)
194 : : {
195 : 14 : int num_groups = nTautomer[0];
196 : :
197 [ + + + - ]: 26 : for (i = 1; i < lenTautomer && num_groups > 0; i += nTautomer[i] + 1, num_groups--)
198 : : {
199 : 12 : num_H += nTautomer[i + 1];
200 : : }
201 : : }
202 : :
203 [ + - ]: 161 : if (mult)
204 : : {
205 [ + + ]: 161 : if (bHydrogen)
206 : : {
207 : 6 : num_H += mult;
208 : : }
209 [ + + ]: 155 : else if (bCarbon)
210 : : {
211 : 11 : num_C += mult;
212 : : }
213 : : else
214 : : {
215 : 144 : nFormLen += nElemLen;
216 : 144 : nFormLen += GetHillFormulaIndexLength( mult );
217 : : }
218 : : }
219 : :
220 [ + + ]: 161 : if (num_C)
221 : : {
222 : 73 : nFormLen += (int) strlen( "C" );
223 : 73 : nFormLen += GetHillFormulaIndexLength( num_C );
224 : : }
225 : :
226 [ + + ]: 161 : if (num_H)
227 : : {
228 : 101 : nFormLen += (int) strlen( "H" );
229 : 101 : nFormLen += GetHillFormulaIndexLength( num_H );
230 : : }
231 : :
232 : 161 : *pnum_C = num_C;
233 : 161 : *pnum_H = num_H;
234 : 161 : *pnLen = nFormLen;
235 : 161 : *pnNumNonHAtoms = nNumNonHAtoms;
236 : :
237 : 161 : return 0;
238 : : }
239 : :
240 : :
241 : : /****************************************************************************
242 : : Add a portion to Hill formula for single component.
243 : : ****************************************************************************/
244 : 367 : int AddElementAndCount( const char *szElement, int mult, char *szLinearCT, int nLenLinearCT, int *bOverflow )
245 : : {
246 : : char szMult[16];
247 : : int len1, len2;
248 [ + - + - : 367 : if (mult > 0 && !*bOverflow && 0 < ( len1 = strlen( szElement ) ))
+ - ]
249 : : {
250 [ + + ]: 367 : if (mult > 1)
251 : : {
252 : 198 : len2 = sprintf(szMult, "%d", mult);
253 : : }
254 : : else
255 : : {
256 : 169 : len2 = 0;
257 : 169 : szMult[0] = '\0';
258 : : }
259 [ + - ]: 367 : if (len1 + len2 < nLenLinearCT)
260 : : {
261 : 367 : memcpy(szLinearCT, szElement, len1);
262 : 367 : memcpy(szLinearCT + len1, szMult, (long long)len2 + 1); /* adding zero termination */ /* djb-rwth: added cast operator */
263 : 367 : return len1 + len2;
264 : : }
265 : : else
266 : : {
267 : 0 : ( *bOverflow )++;
268 : : }
269 : : }
270 : :
271 : 0 : return 0;
272 : : }
273 : :
274 : :
275 : : /****************************************************************************
276 : : Make Hill formula for single component.
277 : :
278 : : If num_C > 0 then nAtom does not contain C or H
279 : : otherwise all elements are in alphabetic order
280 : : ****************************************************************************/
281 : 161 : int MakeHillFormula( U_CHAR *nAtom,
282 : : int num_atoms,
283 : : char *szLinearCT,
284 : : int nLen_szLinearCT,
285 : : int num_C,
286 : : int num_H,
287 : : int *bOverflow )
288 : : {
289 : : char szElement[4];
290 : : int mult, compare2H;
291 : : int i, nLen, bOvfl;
292 : : U_CHAR nPrevAtom;
293 : :
294 : 161 : nLen = 0;
295 : 161 : mult = 0;
296 : 161 : bOvfl = 0;
297 : 161 : nPrevAtom = (U_CHAR) -2; /* non-existent number */
298 : 161 : memset(szElement, '\0', sizeof(szElement)); /* djb-rwth: fixing coverity ID #499542 */
299 : :
300 [ + + ]: 161 : if (num_C)
301 : : {
302 : 73 : nLen += AddElementAndCount( "C", num_C, szLinearCT + nLen, nLen_szLinearCT - nLen, &bOvfl );
303 [ + - ]: 73 : if (num_H)
304 : : {
305 : 73 : nLen += AddElementAndCount( "H", num_H, szLinearCT + nLen, nLen_szLinearCT - nLen, &bOvfl );
306 : 73 : num_H = 0;
307 : : }
308 : : }
309 : :
310 [ + + ]: 494 : for (i = 0; i < num_atoms; i++)
311 : : {
312 : :
313 [ + + ]: 333 : if (nPrevAtom != nAtom[i])
314 : : {
315 [ + + ]: 193 : if (mult)
316 : : {
317 : 46 : nLen += AddElementAndCount( szElement, mult, szLinearCT + nLen, nLen_szLinearCT - nLen, &bOvfl );
318 : : }
319 : 193 : mult = 1;
320 : : /*if (-1 == get_element_chemical_symbol( (int) nAtom[i], szElement ))*/
321 [ - + ]: 193 : if (-1 == get_element_or_pseudoelement_symbol( (int) nAtom[i], szElement ))
322 : : {
323 : 0 : return -1; /* wrong element */
324 : : }
325 : :
326 : 193 : nPrevAtom = nAtom[i];
327 [ - + ]: 193 : if (!strcmp( "C", szElement ))
328 : : {
329 : 0 : return -1;
330 : : }
331 : 193 : compare2H = strcmp( "H", szElement );
332 [ - + ]: 193 : if (!compare2H)
333 : : {
334 : 0 : return -1;
335 : : }
336 [ + + + + ]: 193 : if (compare2H < 0 && num_H)
337 : : {
338 : : /* H-atom should be located in front of szElement */
339 : 15 : nLen += AddElementAndCount( "H", num_H, szLinearCT + nLen, nLen_szLinearCT - nLen, &bOvfl );
340 : 15 : num_H = 0;
341 : : }
342 : : }
343 : : else
344 : : {
345 : 140 : mult++;
346 : : }
347 : : }
348 [ + + ]: 161 : if (mult)
349 : : {
350 : : /* the last element if any */
351 : 147 : nLen += AddElementAndCount( szElement, mult, szLinearCT + nLen, nLen_szLinearCT - nLen, &bOvfl );
352 : : }
353 [ + + ]: 161 : if (num_H)
354 : : {
355 : : /* if H has not been output... */
356 : 13 : nLen += AddElementAndCount( "H", num_H, szLinearCT + nLen, nLen_szLinearCT - nLen, &bOvfl );
357 : : }
358 : 161 : *bOverflow |= ( 0 != bOvfl );
359 : :
360 [ - + ]: 161 : return bOvfl ? nLen_szLinearCT + 1 : nLen;
361 : : }
362 : :
363 : :
364 : : /****************************************************************************
365 : : Allocate space and produce Hill formula for single component
366 : : ****************************************************************************/
367 : 161 : char *AllocateAndFillHillFormula( INChI *pINChI )
368 : : {
369 : : int num_C, num_H, nLen, nNumNonHAtoms, ret, bOverflow;
370 : 161 : char *pHillFormula = NULL;
371 : :
372 : 161 : bOverflow = 0;
373 : :
374 [ + - ]: 161 : if (!GetHillFormulaCounts( pINChI->nAtom,
375 : : pINChI->nNum_H,
376 : : pINChI->nNumberOfAtoms,
377 : : pINChI->nTautomer,
378 : : pINChI->lenTautomer,
379 : : &num_C, &num_H,
380 : : &nLen,
381 : : &nNumNonHAtoms ))
382 : : {
383 : :
384 : : #if ( FIX_GAF_2019_2==1 )
385 : 161 : pHillFormula = (char*)inchi_calloc((long long )nLen + 1, sizeof(char)); /* djb-rwth: cast operator added */
386 : : #else
387 : : pHillFormula = (char*)inchi_malloc(nLen + 1);
388 : : #endif
389 : :
390 [ + - ]: 161 : if (pHillFormula)
391 : : {
392 : :
393 : 161 : ret = MakeHillFormula( pINChI->nAtom + num_C,
394 : : nNumNonHAtoms - num_C,
395 : : pHillFormula,
396 : : nLen + 1,
397 : : num_C, num_H,
398 : : &bOverflow );
399 : :
400 [ + - - + ]: 161 : if (ret != nLen || bOverflow)
401 : : {
402 [ # # ]: 0 : inchi_free( pHillFormula );
403 : 0 : pHillFormula = NULL;
404 : : }
405 : : }
406 : : }
407 : :
408 : 161 : return pHillFormula;
409 : : }
410 : :
411 : :
412 : : /************************************************************************************/
413 : : /* Return value: 0 => copied to stereo bonds; 1=> Allene copied to stereocenters */
414 : : /* on input nNumberOfStereoBonds==NULL means second call, use Stereo->...Inv */
415 : : /************************************************************************************/
416 : 0 : int Copy2StereoBondOrAllene( INChI_Stereo *Stereo,
417 : : int *nNumberOfStereoCenters,
418 : : int *nNumberOfStereoBonds,
419 : : AT_STEREO_DBLE *LinearCTStereoDble,
420 : : AT_NUMB *pCanonOrd,
421 : : AT_RANK *pCanonRank,
422 : : sp_ATOM *at,
423 : : int bIsotopic )
424 : : {
425 : : int cumulene_len,
426 : : j,
427 : 0 : next_j = 0 /* ordering number of the central allene atom */,
428 : : next_neigh;
429 : : AT_RANK
430 : : at_num;
431 : : int parity;
432 : :
433 [ # # # # ]: 0 : if (pCanonOrd && pCanonRank)
434 : : {
435 : 0 : j = pCanonOrd[(int) LinearCTStereoDble->at_num1 - 1];
436 : :
437 : : /* if allene then find the central atom, at[next_j] */
438 : :
439 [ # # ]: 0 : if (bIsotopic)
440 : : {
441 : 0 : cumulene_len = BOND_CHAIN_LEN( at[j].stereo_bond_parity2[0] );
442 : :
443 [ # # # # ]: 0 : if (cumulene_len % 2 && ( 1 >= MAX_NUM_STEREO_BONDS || !at[j].stereo_bond_neighbor2[1] ))
444 : : {
445 : 0 : next_j = at[j].neighbor[(int) at[j].stereo_bond_ord2[0]];
446 : :
447 [ # # # # ]: 0 : for (cumulene_len = ( cumulene_len - 1 ) / 2; cumulene_len && 2 == at[next_j].valence; cumulene_len--)
448 : : {
449 : 0 : next_neigh = ( j == at[next_j].neighbor[0] );
450 : 0 : j = next_j;
451 : 0 : next_j = at[next_j].neighbor[next_neigh];
452 : : }
453 : : /* next_j is the central atom */
454 : : }
455 : : else
456 : : {
457 : 0 : cumulene_len = -1; /* not an allene */
458 : : }
459 : : }
460 : : else
461 : : {
462 : 0 : cumulene_len = BOND_CHAIN_LEN( at[j].stereo_bond_parity[0] );
463 : :
464 [ # # # # ]: 0 : if (cumulene_len % 2 && ( 1 >= MAX_NUM_STEREO_BONDS || !at[j].stereo_bond_neighbor[1] ))
465 : : {
466 : 0 : next_j = at[j].neighbor[(int) at[j].stereo_bond_ord[0]];
467 : :
468 [ # # # # ]: 0 : for (cumulene_len = ( cumulene_len - 1 ) / 2; cumulene_len && 2 == at[next_j].valence; cumulene_len--)
469 : : {
470 : 0 : next_neigh = ( j == at[next_j].neighbor[0] );
471 : 0 : j = next_j;
472 : 0 : next_j = at[next_j].neighbor[next_neigh];
473 : : }
474 : : }
475 : : else
476 : : {
477 : 0 : cumulene_len = -1; /* not an allene */
478 : : }
479 : : }
480 : :
481 [ # # ]: 0 : if (!cumulene_len)
482 : : {
483 : : /* allene has been found; insert new stereocenter and parity */
484 : :
485 : : AT_NUMB *nNumber;
486 : : S_CHAR *t_parity;
487 : :
488 [ # # ]: 0 : nNumber = nNumberOfStereoBonds ? Stereo->nNumber : Stereo->nNumberInv;
489 [ # # ]: 0 : t_parity = nNumberOfStereoBonds ? Stereo->t_parity : Stereo->t_parityInv;
490 : :
491 : 0 : at_num = pCanonRank[next_j];
492 : 0 : parity = LinearCTStereoDble->parity;
493 : :
494 : : /* free room for the new stereocenter */
495 [ # # # # ]: 0 : for (j = 0; j < *nNumberOfStereoCenters && Stereo->nNumber[j] < at_num; j++)
496 : : {
497 : : ;
498 : : }
499 : :
500 [ # # ]: 0 : if (j < *nNumberOfStereoCenters)
501 : : {
502 : 0 : memmove(nNumber + j + 1, nNumber + j, (*nNumberOfStereoCenters - (long long)j) * sizeof(nNumber[0])); /* djb-rwth: cast operator added */
503 : 0 : memmove(t_parity + j + 1, t_parity + j, (*nNumberOfStereoCenters - (long long)j) * sizeof(t_parity[0])); /* djb-rwth: cast operator added */
504 : : }
505 : :
506 : : /* fill the new stereo center info */
507 : :
508 : 0 : nNumber[j] = at_num;
509 : 0 : t_parity[j] = parity;
510 : 0 : ( *nNumberOfStereoCenters )++;
511 : 0 : return 1;
512 : : }
513 : : }
514 : :
515 : : /* Save the stereo bond info */
516 : :
517 [ # # ]: 0 : if (nNumberOfStereoBonds)
518 : : {
519 : 0 : j = *nNumberOfStereoBonds;
520 : 0 : Stereo->b_parity[j] = LinearCTStereoDble->parity;
521 : 0 : Stereo->nBondAtom1[j] = LinearCTStereoDble->at_num1;
522 : 0 : Stereo->nBondAtom2[j] = LinearCTStereoDble->at_num2;
523 : 0 : ( *nNumberOfStereoBonds )++;
524 : : }
525 : :
526 : 0 : return 0;
527 : : }
528 : :
529 : :
530 : : /***************************************************************************/
531 : 55 : int CopyLinearCTStereoToINChIStereo( INChI_Stereo *Stereo,
532 : : AT_STEREO_CARB *LinearCTStereoCarb,
533 : : int nLenLinearCTStereoCarb,
534 : : AT_STEREO_DBLE *LinearCTStereoDble,
535 : : int nLenLinearCTStereoDble,
536 : : AT_NUMB *pCanonOrd, AT_RANK *pCanonRank,
537 : : sp_ATOM *at,
538 : : int bIsotopic,
539 : : AT_STEREO_CARB *LinearCTStereoCarbInv,
540 : : AT_STEREO_DBLE *LinearCTStereoDbleInv,
541 : : AT_NUMB *pCanonOrdInv, AT_RANK *pCanonRankInv )
542 : : {
543 : 55 : int n, i, nErrorCode = 0, len;
544 : : int bAllene;
545 : : int diff;
546 : : int lenInv, bAlleneInv;
547 : :
548 : : /* Stereo centers */
549 : :
550 : : /* djb-rwth: fixing oss-fuzz issue #68271 */
551 [ + - ]: 55 : if (Stereo)
552 : : {
553 : 55 : n = Stereo->nNumberOfStereoCenters = nLenLinearCTStereoCarb;
554 : :
555 [ + + ]: 242 : for (i = 0; i < n; i++)
556 : : {
557 [ + - ]: 187 : if (LinearCTStereoCarb) /* djb-rwth: fixing a NULL pointer dereference */
558 : : {
559 : 187 : Stereo->nNumber[i] = LinearCTStereoCarb[i].at_num;
560 : 187 : Stereo->t_parity[i] = LinearCTStereoCarb[i].parity;
561 : : }
562 [ + - ]: 187 : if (LinearCTStereoCarbInv) /* djb-rwth: fixing a NULL pointer dereference */
563 : : {
564 : 187 : Stereo->nNumberInv[i] = LinearCTStereoCarbInv[i].at_num;
565 : 187 : Stereo->t_parityInv[i] = LinearCTStereoCarbInv[i].parity;
566 : : }
567 : : }
568 : :
569 : : /* Stereo bonds */
570 : :
571 : 55 : n = nLenLinearCTStereoDble;
572 : 55 : lenInv = Stereo->nNumberOfStereoCenters;
573 : :
574 [ - + ]: 55 : for (i = len = 0; i < n; i++)
575 : : {
576 : : bAllene =
577 : 0 : Copy2StereoBondOrAllene(Stereo,
578 : : &Stereo->nNumberOfStereoCenters,
579 : : &len,
580 : 0 : LinearCTStereoDble + i,
581 : : pCanonOrd, pCanonRank,
582 : : at,
583 : : bIsotopic);
584 : :
585 : : bAlleneInv =
586 : 0 : Copy2StereoBondOrAllene(Stereo,
587 : : &lenInv,
588 : : NULL,
589 : 0 : LinearCTStereoDbleInv + i,
590 : : pCanonOrdInv, pCanonRankInv,
591 : : at,
592 : : bIsotopic);
593 : :
594 : : /* make sure double bond stereo is identical in original and inverted geometry */
595 : : /* Note: all allenes are AFTER double bonds in LinearCTStereoDble... */
596 [ # # # # : 0 : if (bAllene != bAlleneInv || (!bAllene &&
# # ]
597 : 0 : CompareLinCtStereoDble(LinearCTStereoDble + i, 1,
598 : 0 : LinearCTStereoDbleInv + i, 1))) /* djb-rwth: addressing LLVM warning */
599 : : {
600 : : /* double bond stereo Inv is NOT identical to Abs */
601 : 0 : nErrorCode = -4;
602 : 0 : goto exit_function;
603 : : }
604 : : }
605 : :
606 : 55 : Stereo->nNumberOfStereoBonds = len;
607 : :
608 [ - + ]: 55 : if (lenInv != Stereo->nNumberOfStereoCenters)
609 : : {
610 : 0 : nErrorCode = -5; /* different number of stereo centers in Abs and Inv */
611 : 0 : goto exit_function;
612 : : }
613 : :
614 : :
615 : : /* compare inverted stereocenters to absolute */
616 : :
617 : 55 : n = Stereo->nNumberOfStereoCenters;
618 : : /* djb-rwth: removing redundant code */
619 : :
620 [ + + ]: 64 : for (i = 0, diff = 0; i < n; i++)
621 : : {
622 [ - + ]: 60 : if (Stereo->nNumberInv[i] != Stereo->nNumber[i])
623 : : {
624 [ # # ]: 0 : diff = (Stereo->nNumberInv[i] > Stereo->nNumber[i]) ? 2 : -2;
625 : 0 : break; /* Abs != Inv */
626 : : }
627 [ + + ]: 60 : if (Stereo->t_parityInv[i] != Stereo->t_parity[i])
628 : : {
629 [ + + ]: 51 : diff = (Stereo->t_parityInv[i] > Stereo->t_parity[i]) ? 1 : -1;
630 : 51 : break; /* Abs != Inv */
631 : : }
632 : : }
633 : :
634 : 55 : Stereo->nCompInv2Abs =
635 [ + + + + ]: 55 : (diff > 0) ? 1 : (diff < 0) ? -1 : 0;
636 : :
637 [ + + + + ]: 55 : if (diff == -1 || diff == 1)
638 : : {
639 : : /* The first found difference was in parities */
640 [ + + ]: 216 : for (i = 0, diff = 0; i < n; i++)
641 : : {
642 [ - + ]: 174 : if (Stereo->nNumberInv[i] != Stereo->nNumber[i])
643 : : {
644 : 0 : diff = 2; /* difference in stereo center numbering */
645 : 0 : break;
646 : : }
647 : :
648 : : /* Parities can be only 1, 2, 3, 4. Therefore only mutually inverted pairs
649 : : * (t_parityInv, t_parity) = (1,2) or (2,1) statisfy conditions
650 : : * (t_parityInv != t_parity) && (t_parityInv + t_parity == 3)
651 : : */
652 : :
653 [ + + ]: 174 : if (Stereo->t_parityInv[i] == Stereo->t_parity[i] ||
654 [ - + ]: 165 : Stereo->t_parityInv[i] + Stereo->t_parity[i] != 3)
655 : : {
656 : 9 : diff = 1; /* parities are same or different and cannot be obtained by simple inversion */
657 : 9 : break;
658 : : }
659 : : }
660 : 51 : Stereo->bTrivialInv = !diff;
661 : : }
662 : : else
663 : : {
664 : 4 : Stereo->bTrivialInv = 0;
665 : : }
666 : : }
667 : : else
668 : : {
669 : 0 : nErrorCode = 1;
670 : : }
671 : :
672 : 55 : exit_function:
673 : 55 : return nErrorCode;
674 : : }
675 : :
676 : :
677 : : /****************************************************************************/
678 : 161 : int MarkAmbiguousStereo( sp_ATOM *at,
679 : : inp_ATOM *norm_at,
680 : : int bIsotopic,
681 : : AT_NUMB *pCanonOrd,
682 : : AT_STEREO_CARB *LinearCTStereoCarb,
683 : : int nLenLinearCTStereoCarb,
684 : : AT_STEREO_DBLE *LinearCTStereoDble,
685 : : int nLenLinearCTStereoDble )
686 : : {
687 : : int n, i, j1, j2, num, mark_atom, mark_bond;
688 : :
689 [ - + ]: 161 : if (!pCanonOrd)
690 : : {
691 : 0 : return -1;
692 : : }
693 : :
694 : 161 : num = 0;
695 : :
696 : 161 : n = nLenLinearCTStereoCarb;
697 : :
698 [ - + ]: 161 : mark_atom = bIsotopic ? AMBIGUOUS_STEREO_ATOM_ISO : AMBIGUOUS_STEREO_ATOM;
699 : :
700 [ + + ]: 348 : for (i = 0; i < n; i++)
701 : : {
702 : : /* Mark ambiguous stereo centers (for displaying and "Ambiguous stereo" message) */
703 [ + - + - : 187 : if (ATOM_PARITY_NOT_UNKN( LinearCTStereoCarb[i].parity ) &&
+ - ]
704 [ - + ]: 187 : at[j1 = pCanonOrd[(int) LinearCTStereoCarb[i].at_num - 1]].bAmbiguousStereo)
705 : : {
706 : 0 : at[j1].bAmbiguousStereo |= mark_atom;
707 : 0 : norm_at[j1].bAmbiguousStereo |= mark_atom;
708 : 0 : num++;
709 : : }
710 : : }
711 : :
712 : 161 : n = nLenLinearCTStereoDble;
713 : :
714 [ - + ]: 161 : mark_bond = bIsotopic ? AMBIGUOUS_STEREO_BOND_ISO : AMBIGUOUS_STEREO_BOND;
715 : :
716 [ - + ]: 161 : for (i = 0; i < n; i++)
717 : : {
718 : : /* Mark ambiguous stereo bonds or allenes (for displaying and "Ambiguous stereo" message) */
719 : :
720 [ # # # # ]: 0 : if (ATOM_PARITY_WELL_DEF( LinearCTStereoDble[i].parity ))
721 : : {
722 : 0 : j1 = pCanonOrd[(int) LinearCTStereoDble[i].at_num1 - 1];
723 : 0 : j2 = pCanonOrd[(int) LinearCTStereoDble[i].at_num2 - 1];
724 : :
725 [ # # # # ]: 0 : if (at[j1].bAmbiguousStereo || at[j2].bAmbiguousStereo)
726 : : {
727 : : /* If it is an allene then mark the central atom only
728 : : because the bonds should not be marked to avoid misleading
729 : : message "Ambiguous stereo: bond(s)": Allene makes a stereocenter
730 : : */
731 : :
732 [ # # ]: 0 : int j1_parity = bIsotopic ? at[j1].stereo_bond_parity2[0] : at[j1].stereo_bond_parity[0];
733 : :
734 : 0 : int cumulene_len = BOND_CHAIN_LEN( j1_parity ); /* 0 => double bond, 1 => allene, 2 => cumulene,..*/
735 : :
736 [ # # # # : 0 : if (cumulene_len % 2 && ( 1 >= MAX_NUM_STEREO_BONDS ||
# # ]
737 : 0 : !( bIsotopic ? at[j1].stereo_bond_neighbor2[1] : at[j1].stereo_bond_neighbor[1] ) )
738 : : )
739 : : {
740 : : /* found an allene; locate its central atom */
741 : :
742 : : int next_j, next_neigh;
743 : 0 : int j = j1;
744 : :
745 [ # # ]: 0 : next_j = at[j].neighbor[bIsotopic ? at[j].stereo_bond_ord2[0] : at[j].stereo_bond_ord[0]];
746 : :
747 : 0 : for (cumulene_len = ( cumulene_len - 1 ) / 2;
748 [ # # # # ]: 0 : cumulene_len && 2 == at[next_j].valence;
749 : 0 : cumulene_len--)
750 : : {
751 : 0 : next_neigh = ( j == at[next_j].neighbor[0] );
752 : 0 : j = next_j;
753 : 0 : next_j = at[next_j].neighbor[next_neigh];
754 : : }
755 : : /* next_j is the central atom */
756 [ # # ]: 0 : if (2 == at[next_j].valence)
757 : : {
758 : 0 : at[next_j].bAmbiguousStereo |= mark_atom;
759 : 0 : norm_at[next_j].bAmbiguousStereo |= mark_atom;
760 : 0 : num++;
761 : 0 : continue; /* do not mark the cumulene "bond" endpoints */
762 : : }
763 : : }
764 : :
765 : : /* Not an allene, mark double bond or cumulene end atoms */
766 [ # # ]: 0 : if (at[j1].bAmbiguousStereo)
767 : : {
768 : 0 : at[j1].bAmbiguousStereo |= mark_bond; /* ??? */
769 : 0 : norm_at[j1].bAmbiguousStereo |= mark_bond;
770 : 0 : num++;
771 : : }
772 : :
773 [ # # ]: 0 : if (at[j2].bAmbiguousStereo)
774 : : {
775 : 0 : at[j2].bAmbiguousStereo |= mark_bond; /* ??? */
776 : 0 : norm_at[j2].bAmbiguousStereo |= mark_bond;
777 : 0 : num++;
778 : : }
779 : : }
780 : : }
781 : : }
782 : :
783 : 161 : return num;
784 : : }
785 : :
786 : :
787 : : /****************************************************************************/
788 : 161 : INCHI_MODE UnmarkAllUndefinedUnknownStereo( INChI_Stereo *Stereo,
789 : : INCHI_MODE nUserMode )
790 : : {
791 : 161 : INCHI_MODE nRet = 0;
792 : : int i, n;
793 : :
794 [ + - + - : 161 : if (!Stereo || (Stereo && !Stereo->nNumberOfStereoCenters && !Stereo->nNumberOfStereoBonds)) /* djb-rwth: addressing LLVM warning */
+ + + - ]
795 : : {
796 : 106 : return nRet;
797 : : }
798 : :
799 : : /* Stereocenters */
800 [ + + ]: 55 : if (!Stereo->nCompInv2Abs &&
801 [ + - + - ]: 4 : ( n = Stereo->nNumberOfStereoCenters ) > 0 && ( nUserMode & REQ_MODE_SC_IGN_ALL_UU ))
802 : : {
803 : :
804 [ + + - + : 11 : for (i = 0; i < n && !ATOM_PARITY_WELL_DEF( Stereo->t_parity[i] ); i++)
+ - ]
805 : : {
806 : : ;
807 : : }
808 : :
809 [ + - ]: 4 : if (i == n)
810 : : {
811 : 4 : Stereo->nNumberOfStereoCenters = 0;
812 : :
813 [ + + ]: 11 : for (i = 0; i < n; i++)
814 : : {
815 : 7 : Stereo->t_parity[i] = 0;
816 : 7 : Stereo->nNumber[i] = 0;
817 : 7 : Stereo->t_parityInv[i] = 0;
818 : 7 : Stereo->nNumberInv[i] = 0;
819 : : }
820 : :
821 : 4 : nRet |= REQ_MODE_SC_IGN_ALL_UU;
822 : : }
823 : : }
824 : :
825 : : /* Stereobonds */
826 : :
827 [ - + - - ]: 55 : if (( n = Stereo->nNumberOfStereoBonds ) > 0 && ( nUserMode & REQ_MODE_SB_IGN_ALL_UU ))
828 : : {
829 [ # # # # : 0 : for (i = 0; i < n && !ATOM_PARITY_WELL_DEF( Stereo->b_parity[i] ); i++)
# # ]
830 : : {
831 : : ;
832 : : }
833 : :
834 [ # # ]: 0 : if (i == n)
835 : : {
836 : 0 : Stereo->nNumberOfStereoBonds = 0;
837 [ # # ]: 0 : for (i = 0; i < n; i++)
838 : : {
839 : 0 : Stereo->b_parity[i] = 0;
840 : 0 : Stereo->nBondAtom1[i] = 0;
841 : 0 : Stereo->nBondAtom2[i] = 0;
842 : : }
843 : 0 : nRet |= REQ_MODE_SB_IGN_ALL_UU;
844 : : }
845 : : }
846 : :
847 : 55 : return nRet;
848 : : }
849 : :
850 : :
851 : : #if ( defined(TARGET_API_LIB) )
852 : :
853 : :
854 : : /****************************************************************************/
855 : 0 : void WriteCoord( char *str, double x )
856 : : {
857 [ # # ]: 0 : if (x < -9999999.9)
858 : : {
859 : : #ifdef GHI100_FIX
860 : : #if (SPRINTF_FLAG == 2)
861 : : dbl2int(str, 10, 2, 'e', x);
862 : : #elif (SPRINTF_FLAG == 1)
863 : : stbsp_sprintf(str, "%10.2e", x);
864 : : #else
865 : : sprintf(str, "%10.2e", x);
866 : : #endif
867 : : #endif
868 : 0 : sprintf(str, "%10.2e", x);
869 : : }
870 : : else
871 : : {
872 [ # # ]: 0 : if (x < -999999.99)
873 : : {
874 : : #ifdef GHI100_FIX
875 : : #if (SPRINTF_FLAG == 2)
876 : : dbl2int(str, 10, 2, 'f', x);
877 : : #elif (SPRINTF_FLAG == 1)
878 : : stbsp_sprintf(str, "%10.2f", x);
879 : : #else
880 : : sprintf( str, "%10.2f", x );
881 : : #endif
882 : : #endif
883 : 0 : sprintf( str, "%10.2f", x );
884 : : }
885 : : else
886 : : {
887 [ # # ]: 0 : if (x < -99999.999)
888 : : {
889 : : #ifdef GHI100_FIX
890 : : #if (SPRINTF_FLAG == 2)
891 : : dbl2int(str, 10, 3, 'f', x);
892 : : #elif (SPRINTF_FLAG == 1)
893 : : stbsp_sprintf(str, "%10.3f", x);
894 : : #else
895 : : sprintf( str, "%10.3f", x );
896 : : #endif
897 : : #endif
898 : 0 : sprintf( str, "%10.3f", x );
899 : : }
900 : : else
901 : : {
902 [ # # ]: 0 : if (x < 99999.9999)
903 : : {
904 : : #ifdef GHI100_FIX
905 : : #if (SPRINTF_FLAG == 2)
906 : : dbl2int(str, 10, 4, 'f', x);
907 : : #elif (SPRINTF_FLAG == 1)
908 : : stbsp_sprintf(str, "%10.4f", x);
909 : : #else
910 : : sprintf( str, "%10.4f", x );
911 : : #endif
912 : : #endif
913 : 0 : sprintf( str, "%10.4f", x );
914 : : }
915 : : else
916 : : {
917 [ # # ]: 0 : if (x < 999999.999)
918 : : {
919 : : #ifdef GHI100_FIX
920 : : #if (SPRINTF_FLAG == 2)
921 : : dbl2int(str, 10, 3, 'f', x);
922 : : #elif (SPRINTF_FLAG == 1)
923 : : stbsp_sprintf(str, "%10.3f", x);
924 : : #else
925 : : sprintf( str, "%10.3f", x );
926 : : #endif
927 : : #endif
928 : 0 : sprintf( str, "%10.3f", x );
929 : : }
930 : : else
931 : : {
932 [ # # ]: 0 : if (x < 9999999.99)
933 : : {
934 : : #ifdef GHI100_FIX
935 : : #if (SPRINTF_FLAG == 2)
936 : : dbl2int(str, 10, 2, 'f', x);
937 : : #elif (SPRINTF_FLAG == 1)
938 : : stbsp_sprintf(str, "%10.2f", x);
939 : : #else
940 : : sprintf( str, "%10.2f", x );
941 : : #endif
942 : : #endif
943 : 0 : sprintf( str, "%10.2f", x );
944 : : }
945 : : else
946 : : {
947 [ # # ]: 0 : if (x < 99999999.9)
948 : : {
949 : : #ifdef GHI100_FIX
950 : : #if (SPRINTF_FLAG == 2)
951 : : dbl2int(str, 10, 1, 'f', x);
952 : : #elif (SPRINTF_FLAG == 1)
953 : : stbsp_sprintf(str, "%10.1f", x);
954 : : #else
955 : : sprintf( str, "%10.1f", x );
956 : : #endif
957 : : #endif
958 : 0 : sprintf( str, "%10.1f", x );
959 : : }
960 : : else
961 : : {
962 : : #ifdef GHI100_FIX
963 : : #if (SPRINTF_FLAG == 2)
964 : : dbl2int(str, 10, 3, 'e', x);
965 : : #elif (SPRINTF_FLAG == 1)
966 : : stbsp_sprintf(str, "%10.3e", x);
967 : : #else
968 : : sprintf( str, "%10.3e", x );
969 : : #endif
970 : : #endif
971 : 0 : sprintf( str, "%10.3e", x );
972 : : }
973 : : }
974 : : }
975 : : }
976 : : }
977 : : }
978 : : }
979 : 0 : }
980 : : #endif
981 : :
982 : :
983 : :
984 : : /* used CANON_STAT members
985 : :
986 : : pCS->LinearCT
987 : : pCS->LinearCTIsotopic
988 : : pCS->LinearCTIsotopicStereoCarb
989 : : pCS->LinearCTIsotopicStereoCarbInv
990 : : pCS->LinearCTIsotopicStereoDble
991 : : pCS->LinearCTIsotopicStereoDbleInv
992 : : pCS->LinearCTIsotopicTautomer
993 : : pCS->LinearCTStereoCarb
994 : : pCS->LinearCTStereoCarbInv
995 : : pCS->LinearCTStereoDble
996 : : pCS->LinearCTStereoDbleInv
997 : : pCS->nCanonOrd
998 : : pCS->nCanonOrdIsotopic
999 : : pCS->nCanonOrdIsotopicStereo
1000 : : pCS->nCanonOrdIsotopicStereoInv
1001 : : pCS->nCanonOrdIsotopicStereoTaut
1002 : : pCS->nCanonOrdIsotopicTaut
1003 : : pCS->nCanonOrdStereo
1004 : : pCS->nCanonOrdStereoInv
1005 : : pCS->nCanonOrdStereoTaut
1006 : : pCS->nCanonOrdTaut
1007 : : pCS->nLenCanonOrd
1008 : : pCS->nLenCanonOrdIsotopic
1009 : : pCS->nLenCanonOrdIsotopicStereo
1010 : : pCS->nLenCanonOrdIsotopicStereoTaut
1011 : : pCS->nLenCanonOrdIsotopicTaut
1012 : : pCS->nLenCanonOrdStereo
1013 : : pCS->nLenCanonOrdStereoTaut
1014 : : pCS->nLenCanonOrdTaut
1015 : : pCS->nLenLinearCTAtOnly
1016 : : pCS->nLenLinearCTIsotopic
1017 : : pCS->nLenLinearCTIsotopicStereoCarb
1018 : : pCS->nLenLinearCTIsotopicStereoDble
1019 : : pCS->nLenLinearCTIsotopicTautomer
1020 : : pCS->nLenLinearCTStereoCarb
1021 : : pCS->nLenLinearCTStereoDble
1022 : : pCS->nNum_H
1023 : : pCS->nNum_H_fixed
1024 : : pCS->nSymmRank
1025 : : pCS->nSymmRankIsotopic
1026 : : pCS->nSymmRankIsotopicTaut
1027 : : pCS->nSymmRankTaut
1028 : : pCS->t_group_info
1029 : : pCS->t_group_info->num_t_groups
1030 : :
1031 : : */
1032 : :
1033 : :
1034 : : /****************************************************************************
1035 : : Serialization: one-component InChI
1036 : : ****************************************************************************/
1037 : 161 : int FillOutINChI( INChI *pINChI,
1038 : : INChI_Aux *pINChI_Aux,
1039 : : int num_atoms,
1040 : : int num_at_tg,
1041 : : int num_removed_H,
1042 : : sp_ATOM *at,
1043 : : inp_ATOM *norm_at,
1044 : : CANON_STAT *pCS,
1045 : : CANON_GLOBALS *pCG,
1046 : : int bTautomeric,
1047 : : INCHI_MODE nUserMode,
1048 : : char *pStrErrStruct,
1049 : : int bNoWarnings )
1050 : : {
1051 : 161 : int i, j, m, n, g, len, ii, ret = 0;
1052 : :
1053 : 161 : AT_NUMB *pSymmRank, *pOrigNosInCanonOrd, *pConstitEquNumb, *pCanonOrd = NULL, *pCanonOrdInv = NULL, *pCanonOrdTaut;
1054 : 161 : T_GROUP_INFO *t_group_info = pCS->t_group_info;
1055 : : T_GROUP *t_group;
1056 : :
1057 : 161 : int nErrorCode = 0;
1058 : : AT_NUMB *pCanonRank, *pCanonRankInv; /* canonical ranks of the atoms or tautomeric groups */
1059 : 161 : AT_NUMB *pCanonRankAtoms = NULL, *pSortOrd = NULL;
1060 : : AT_RANK nMinOrd;
1061 : :
1062 : : INChI_Stereo *Stereo;
1063 : 161 : int bUseNumberingInv = 0, bUseIsotopicNumberingInv = 0;
1064 : :
1065 : : INCHI_MODE nStereoUnmarkMode;
1066 : :
1067 : : /*AT_NUMB *pCanonOrdNonIso = NULL, *pCanonOrdIso = NULL;*/
1068 : : /*AT_NUMB *nOrigAtNosInCanonOrdNonIso = NULL, *nOrigAtNosInCanonOrdIso = NULL;*/
1069 : :
1070 : :
1071 : : /* Check for warnings */
1072 [ + - + - ]: 161 : if (pCS->nLenLinearCTStereoCarb < 0 || pCS->nLenLinearCTStereoDble < 0 ||
1073 [ + - - + ]: 161 : pCS->nLenCanonOrdStereo < 0 || pCS->nLenCanonOrdStereoTaut < 0)
1074 : : {
1075 : 0 : nErrorCode |= WARN_FAILED_STEREO;
1076 : : }
1077 [ + - + - ]: 161 : if (pCS->nLenLinearCTIsotopic < 0 || pCS->nLenLinearCTIsotopicTautomer < 0 ||
1078 [ + - - + ]: 161 : pCS->nLenCanonOrdIsotopic < 0 || pCS->nLenCanonOrdIsotopicTaut < 0)
1079 : : {
1080 : 0 : nErrorCode |= WARN_FAILED_ISOTOPIC;
1081 : : }
1082 [ + - + - ]: 161 : if (pCS->nLenLinearCTIsotopicStereoCarb < 0 || pCS->nLenLinearCTIsotopicStereoDble < 0 ||
1083 [ + - - + ]: 161 : pCS->nLenCanonOrdIsotopicStereo < 0 || pCS->nLenCanonOrdIsotopicStereoTaut < 0)
1084 : : {
1085 : 0 : nErrorCode |= WARN_FAILED_ISOTOPIC_STEREO;
1086 : : }
1087 : :
1088 : 161 : pCanonRankAtoms = (AT_NUMB *) inchi_calloc( (long long)num_at_tg + 1, sizeof( pCanonRankAtoms[0] ) ); /* djb-rwth: cast operator added */
1089 : :
1090 : 161 : pSortOrd = (AT_NUMB *) inchi_calloc( (long long)num_at_tg + 1, sizeof( pSortOrd[0] ) ); /* must have more than num_atoms */ /* djb-rwth: cast operator added */
1091 : :
1092 [ + - - + ]: 161 : if (!pCanonRankAtoms || !pSortOrd)
1093 : : {
1094 : 0 : nErrorCode = 0;
1095 : 0 : ret = CT_OUT_OF_RAM; /* <BRKPT> */
1096 : 0 : pINChI->nErrorCode = pINChI_Aux->nErrorCode = CT_OUT_OF_RAM;
1097 : 0 : goto exit_function;
1098 : : }
1099 : :
1100 : : /* Total charge */
1101 : : /* djb-rwth: fixing oss-fuzz issue #69656 */
1102 [ + + ]: 971 : for (i = 0, n = 0; i < num_atoms + num_removed_H; i++)
1103 : : {
1104 : 810 : n += at[i].charge;
1105 : : }
1106 : 161 : pINChI->nTotalCharge = n;
1107 : :
1108 : : /* Number of atoms */
1109 : 161 : pINChI->nNumberOfAtoms = num_atoms;
1110 : 161 : pINChI_Aux->nNumberOfAtoms = num_atoms;
1111 : :
1112 : : /* Removed protons and detachable isotopic H */
1113 [ + - + - ]: 161 : if (bTautomeric && t_group_info)
1114 : : {
1115 : 161 : pINChI_Aux->nNumRemovedProtons = t_group_info->tni.nNumRemovedProtons;
1116 : :
1117 [ + + ]: 644 : for (i = 0; i < NUM_H_ISOTOPES; i++)
1118 : : {
1119 : 483 : pINChI_Aux->nNumRemovedIsotopicH[i] = t_group_info->num_iso_H[i]
1120 : 483 : + t_group_info->tni.nNumRemovedProtonsIsotopic[i];
1121 : : }
1122 : :
1123 [ - + ]: 161 : if (pINChI_Aux->bNormalizationFlags & FLAG_FORCE_SALT_TAUT)
1124 : : {
1125 : 0 : pINChI->nFlags |= INCHI_FLAG_HARD_ADD_REM_PROTON;
1126 : : }
1127 [ + + ]: 161 : if (pINChI_Aux->bNormalizationFlags & ( FLAG_NORM_CONSIDER_TAUT &~FLAG_PROTON_CHARGE_CANCEL ))
1128 : : {
1129 [ + - ]: 14 : if (!bNoWarnings)
1130 : : {
1131 : 14 : WarningMessage( pStrErrStruct, "Proton(s) added/removed" );
1132 : : }
1133 : : }
1134 [ - + ]: 161 : if (pINChI_Aux->bNormalizationFlags & FLAG_PROTON_CHARGE_CANCEL)
1135 : : {
1136 [ # # ]: 0 : if (!bNoWarnings)
1137 : : {
1138 : 0 : WarningMessage( pStrErrStruct, "Charges neutralized" );
1139 : : }
1140 : : }
1141 : : }
1142 : :
1143 : : /* Abs or rel stereo may establish one of two canonical numberings */
1144 [ + + - + ]: 161 : if (( pCS->nLenLinearCTStereoCarb > 0 || pCS->nLenLinearCTStereoDble > 0 ) &&
1145 [ + - ]: 55 : pCS->nLenCanonOrdStereo > 0 &&
1146 [ + - - + ]: 55 : ( (pCS->LinearCTStereoCarb && pCS->LinearCTStereoCarbInv) ||
1147 [ # # # # ]: 0 : (pCS->LinearCTStereoDble && pCS->LinearCTStereoDbleInv) ) &&
1148 [ + - + - ]: 55 : pCS->nCanonOrdStereo && pCS->nCanonOrdStereoInv
1149 : : ) /* djb-rwth: addressing LLVM warning */
1150 : : {
1151 : 55 : pCanonRank = pCanonRankAtoms;
1152 : 55 : pCanonOrd = pCS->nCanonOrdStereo;
1153 : 55 : pCanonRankInv = pSortOrd;
1154 : 55 : pCanonOrdInv = pCS->nCanonOrdStereoInv;
1155 : 55 : Stereo = pINChI->Stereo;
1156 : :
1157 [ + + ]: 611 : for (i = 0; i < num_at_tg; i++)
1158 : : {
1159 : 556 : pCanonRankInv[pCanonOrdInv[i]] =
1160 : 556 : pCanonRank[pCanonOrd[i]] = (AT_NUMB) ( i + 1 );
1161 : : }
1162 : :
1163 : : /********************************************************************/
1164 : : /* Copy stereo bonds and stereo centers; compare Inv and Abs stereo */
1165 : : /********************************************************************/
1166 : :
1167 : 55 : nErrorCode = CopyLinearCTStereoToINChIStereo( Stereo,
1168 : : pCS->LinearCTStereoCarb,
1169 : : pCS->nLenLinearCTStereoCarb,
1170 : : pCS->LinearCTStereoDble,
1171 : : pCS->nLenLinearCTStereoDble,
1172 : : pCanonOrd, pCanonRank,
1173 : : at, 0 /* non-isotopic */,
1174 : : pCS->LinearCTStereoCarbInv,
1175 : : pCS->LinearCTStereoDbleInv,
1176 : : pCanonOrdInv, pCanonRankInv );
1177 : :
1178 : : /* djb-rwth: fixing oss-fuzz issue #68271 */
1179 [ - + ]: 55 : if (nErrorCode == 1)
1180 : : {
1181 : 0 : nErrorCode = 0;
1182 : 0 : ret = CT_OUT_OF_RAM; /* <BRKPT> */
1183 : 0 : pINChI->nErrorCode = pINChI_Aux->nErrorCode = CT_OUT_OF_RAM;
1184 : 0 : goto exit_function;
1185 : : }
1186 : :
1187 [ + - + - ]: 55 : if (Stereo->t_parityInv && Stereo->nNumberInv)
1188 : : {
1189 [ - + ]: 55 : if (nUserMode & REQ_MODE_RELATIVE_STEREO)
1190 : : {
1191 : 0 : pINChI->nFlags |= INCHI_FLAG_REL_STEREO;
1192 : : }
1193 [ - + ]: 55 : if (nUserMode & REQ_MODE_RACEMIC_STEREO)
1194 : : {
1195 : 0 : pINChI->nFlags |= INCHI_FLAG_RAC_STEREO;
1196 : : }
1197 [ + + ]: 55 : if (Stereo->nCompInv2Abs)
1198 : : {
1199 [ + + ]: 51 : if (Stereo->nCompInv2Abs == -1)
1200 : : {
1201 : : /* switch pointers in Stereo so that the stereo becomes the smallest (relative) */
1202 : : /* flag Stereo->nCompInv2Abs == -1 will keep track of this exchange */
1203 : 19 : AT_NUMB *nNumberInv = Stereo->nNumberInv;
1204 : 19 : S_CHAR *t_parityInv = Stereo->t_parityInv;
1205 : 19 : Stereo->nNumberInv = Stereo->nNumber;
1206 : 19 : Stereo->t_parityInv = Stereo->t_parity;
1207 : 19 : Stereo->nNumber = nNumberInv;
1208 : 19 : Stereo->t_parity = t_parityInv;
1209 : : /* switch pointers to set rel. stereo to pINChI_Aux->nOrigAtNosInCanonOrd
1210 : : and inv. stereo to pINChI_Aux->nOrigAtNosInCanonOrdInv */
1211 : 19 : switch_ptrs( &pCanonRank, &pCanonRankInv );
1212 : 19 : switch_ptrs( &pCanonOrd, &pCanonOrdInv );
1213 : 19 : bUseNumberingInv = 1; /* use inverted stereo numbering instead of normal */
1214 : : }
1215 : : }
1216 : : }
1217 : :
1218 : : LOG_NO_ARGS("************************** Canonical Ordering with Stereo (L1183:ichimak2.c) ***************************\n");
1219 [ + + ]: 611 : for (i = 0; i < num_atoms; i++)
1220 : : {
1221 : 556 : pINChI_Aux->nOrigAtNosInCanonOrdInv[i] = at[pCanonOrdInv[i]].orig_at_number;
1222 : 556 : pINChI_Aux->nOrigAtNosInCanonOrd[i] = at[pCanonOrd[i]].orig_at_number;
1223 : : LOG_MULT_ARGS("Atom Nr: %d, Canonical Numbering Normal: %d, Element Name: %s\n", i + 1, at[pCanonOrd[i]].orig_at_number, at[i].elname);
1224 : : }
1225 : :
1226 : : LOG_NO_ARGS("\n******************************************************************************************************\n");
1227 : :
1228 [ + + ]: 55 : if (bUseNumberingInv)
1229 : : {
1230 : : /* switch ptrs back to avoid confusion */
1231 : 19 : switch_ptrs( &pCanonRank, &pCanonRankInv );
1232 : 19 : switch_ptrs( &pCanonOrd, &pCanonOrdInv );
1233 : : /* save inverted stereo ranks & order because it represents the smallest (relative) */
1234 : 19 : memcpy(pCanonRank, pCanonRankInv, num_at_tg * sizeof(pCanonRank[0]));
1235 : : /* change pCS->nCanonOrdStereo[] to inverted: */
1236 : 19 : memcpy(pCanonOrd, pCanonOrdInv, num_at_tg * sizeof(pCanonOrd[0]));
1237 : : }
1238 : :
1239 : 55 : pCanonRankInv = NULL;
1240 : 55 : pCanonOrdInv = NULL;
1241 : 55 : pOrigNosInCanonOrd = NULL;
1242 : : }
1243 : : else
1244 : : {
1245 : : /*------------------------------ no stereo */
1246 : 212 : pCanonOrd = pCS->nLenCanonOrdStereo > 0 ? pCS->nCanonOrdStereo
1247 [ + + + - ]: 106 : : pCS->nLenCanonOrd > 0 ? pCS->nCanonOrd
1248 : : : NULL;
1249 : 106 : pCanonRank = pCanonRankAtoms;
1250 : 106 : pOrigNosInCanonOrd = pINChI_Aux->nOrigAtNosInCanonOrd;
1251 : :
1252 [ + - + - ]: 106 : if (pCanonOrd && pCanonRank)
1253 : : {
1254 [ + + ]: 360 : for (i = 0; i < num_atoms; i++)
1255 : : {
1256 : 254 : pCanonRank[pCanonOrd[i]] = (AT_NUMB) ( i + 1 );
1257 : 254 : pOrigNosInCanonOrd[i] = at[pCanonOrd[i]].orig_at_number;
1258 : : }
1259 [ + + ]: 118 : for (; i < num_at_tg; i++)
1260 : : {
1261 : 12 : pCanonRank[pCanonOrd[i]] = (AT_NUMB) ( i + 1 );
1262 : : }
1263 : : }
1264 : : }
1265 : : /*pCanonOrdNonIso = pCanonOrd;*/ /* save for aux info */
1266 : :
1267 : :
1268 [ + - ]: 161 : if (pINChI_Aux->OrigInfo)
1269 : : {
1270 : : /* charges, radicals, valences */
1271 [ + + ]: 971 : for (i = 0; i < num_atoms; i++)
1272 : : {
1273 [ + - ]: 810 : if (pCanonOrd) /* djb-rwth: fixing a NULL pointer dereference */
1274 : : {
1275 : 810 : ii = pCanonOrd[i];
1276 [ + + + + ]: 810 : if (norm_at[ii].valence || norm_at[ii].num_H)
1277 : : {
1278 : 750 : pINChI_Aux->OrigInfo[i].cCharge = norm_at[ii].charge;
1279 : :
1280 [ + - ]: 1500 : pINChI_Aux->OrigInfo[i].cRadical = (norm_at[ii].radical == RADICAL_SINGLET) ? 0 :
1281 [ + - ]: 750 : (norm_at[ii].radical == RADICAL_DOUBLET) ? 1 :
1282 [ + - ]: 750 : (norm_at[ii].radical == RADICAL_TRIPLET) ? 2 :
1283 [ - + ]: 750 : norm_at[ii].radical ? 3 : 0;
1284 : :
1285 : 750 : pINChI_Aux->OrigInfo[i].cUnusualValence =
1286 : 750 : get_unusual_el_valence(norm_at[ii].el_number, norm_at[ii].charge, norm_at[ii].radical,
1287 : 750 : norm_at[ii].chem_bonds_valence, norm_at[ii].num_H, norm_at[ii].valence);
1288 : : }
1289 : : else
1290 : : {
1291 : : /* charge of a single atom component is in the INChI; valence = 0 is standard */
1292 [ + - ]: 120 : pINChI_Aux->OrigInfo[i].cRadical = (norm_at[ii].radical == RADICAL_SINGLET) ? 0 :
1293 [ + - ]: 60 : (norm_at[ii].radical == RADICAL_DOUBLET) ? 1 :
1294 [ + - ]: 60 : (norm_at[ii].radical == RADICAL_TRIPLET) ? 2 :
1295 [ - + ]: 60 : norm_at[ii].radical ? 3 : 0;
1296 : : }
1297 : : }
1298 : : }
1299 : : }
1300 : :
1301 : : /* Non-isotopic canonical numbers and equivalence of atoms (Aux) */
1302 : 161 : pConstitEquNumb = pINChI_Aux->nConstitEquNumbers; /* contitutional equivalence */
1303 : 161 : pSymmRank = pCS->nSymmRank;
1304 : :
1305 [ + - + - : 161 : if (pCanonOrd && pCanonRank && pSymmRank && pConstitEquNumb)
+ - + - ]
1306 : : {
1307 [ + + ]: 971 : for (i = 0; i < num_atoms; i++)
1308 : : {
1309 : 810 : pConstitEquNumb[i] = pSymmRank[pCanonOrd[i]]; /* constit. equ. ranks in order of canonical numbers */
1310 : 810 : pSortOrd[i] = i;
1311 : : }
1312 [ + + ]: 173 : for (; i < num_at_tg; i++)
1313 : : {
1314 : 12 : pSortOrd[i] = MAX_ATOMS; /* for debugging only */
1315 : : }
1316 : :
1317 : 161 : pCG->m_pn_RankForSort = pConstitEquNumb;
1318 : 161 : inchi_qsort( pCG, pSortOrd, num_atoms, sizeof( pSortOrd[0] ), CompRanksOrd );
1319 : :
1320 [ + + ]: 971 : for (i = 0, nMinOrd = pSortOrd[0], j = 1; j <= num_atoms; j++)
1321 : : {
1322 [ + + + + ]: 810 : if (j == num_atoms || pConstitEquNumb[pSortOrd[i]] != pConstitEquNumb[pSortOrd[j]])
1323 : : {
1324 : 711 : nMinOrd++;
1325 [ + + ]: 711 : if (j - i > 1)
1326 : : {
1327 : : /* found a sequence of equivalent atoms: i..j-1 */
1328 [ + + ]: 235 : while (i < j)
1329 : : {
1330 : 167 : pConstitEquNumb[pSortOrd[i++]] = nMinOrd; /* = min. canon. rank in the group of equ. atoms */
1331 : : }
1332 : : /* at this point j == i */
1333 : : }
1334 : : else
1335 : : {
1336 : 643 : pConstitEquNumb[pSortOrd[i++]] = 0; /* means the atom is not equivalent to any other */
1337 : : }
1338 : 711 : nMinOrd = pSortOrd[j]; /* at the end j = num_atoms */
1339 : : }
1340 : : }
1341 : : }
1342 : :
1343 : : else
1344 : : {
1345 : 0 : nErrorCode |= ERR_NO_CANON_RESULTS;
1346 : 0 : ret = -1; /* program error; no breakpoint here */
1347 : 0 : goto exit_function;
1348 : : }
1349 : :
1350 : :
1351 : : /* Atomic numbers from the Periodic Table */
1352 [ + + ]: 971 : for (i = 0; i < num_atoms; i++)
1353 : : {
1354 : 810 : pINChI->nAtom[i] = (int) at[pCanonOrd[i]].el_number;
1355 : : }
1356 : :
1357 : :
1358 : : /* Connection table: atoms only (before 7-29-2003 pCS->LinearCT2 contained non-isotopic CT) */
1359 [ + - + - : 161 : if (pCS->nLenLinearCTAtOnly <= 0 || !pCS->LinearCT || !pINChI->nConnTable)
- + ]
1360 : : {
1361 : 0 : nErrorCode |= ERR_NO_CANON_RESULTS;
1362 : 0 : ret = -2;
1363 : 0 : goto exit_function;
1364 : : }
1365 : :
1366 : 161 : memcpy(pINChI->nConnTable, pCS->LinearCT, sizeof(pINChI->nConnTable[0]) * pCS->nLenLinearCTAtOnly);
1367 : :
1368 : 161 : pINChI->lenConnTable = pCS->nLenLinearCTAtOnly;
1369 : :
1370 : : /* Tautomeric group(s) canonical representation */
1371 : 161 : len = 0;
1372 [ + - + + ]: 161 : if (bTautomeric && 0 < ( n = SortTautomerGroupsAndEndpoints(
1373 : : pCG, t_group_info,
1374 : : num_atoms, num_at_tg, pCanonRank ) ))
1375 : : {
1376 : : /* SortTautomerGroupsAndEndpoints() produces canonically ordered t-groups */
1377 : 14 : pINChI->nFlags |=
1378 : 7 : ( t_group_info->bTautFlagsDone & TG_FLAG_ALL_SALT_DONE ) ? INCHI_FLAG_ACID_TAUT
1379 [ - + ]: 7 : : 0;
1380 : :
1381 : : /* number of tautomeric groups */
1382 : 7 : pINChI->nTautomer[len++] = (AT_NUMB) n;
1383 : :
1384 : : /* store each tautomeric group, one by one */
1385 [ + + ]: 19 : for (i = 0; i < n; i++)
1386 : : {
1387 : 12 : g = (int) t_group_info->tGroupNumber[i]; /* original group numbers in sorted order */
1388 : 12 : t_group = t_group_info->t_group + g; /* pointer to the tautomeric group */
1389 : :
1390 : : /* NumAt+INCHI_T_NUM_MOVABLE (group length excluding this number) */
1391 : :
1392 : 12 : pINChI->nTautomer[len++] = t_group->nNumEndpoints + INCHI_T_NUM_MOVABLE;
1393 : :
1394 : : /* Num(H), Num(-) */
1395 : :
1396 [ + + ]: 36 : for (j = 0; j < INCHI_T_NUM_MOVABLE; j++) /* djb-rwth: redundant condition; && j < T_NUM_NO_ISOTOPIC part should be checked; can INCHI_T_NUM_MOVABLE and T_NUM_NO_ISOTOPIC change values from 2? */
1397 : : {
1398 : 24 : pINChI->nTautomer[len++] = t_group->num[j];
1399 : : }
1400 : :
1401 : :
1402 : : /* djb-rwth: erroneous loop execution condition
1403 : :
1404 : : for (j = T_NUM_NO_ISOTOPIC; j < INCHI_T_NUM_MOVABLE; j++)
1405 : : {
1406 : : pINChI->nTautomer[len++] = 0; // should not happen
1407 : : }
1408 : :
1409 : : */
1410 : :
1411 : : /* tautomeric group endpoint canonical numbers, pre-sorted in ascending order */
1412 : :
1413 : 12 : for (j = (int) t_group->nFirstEndpointAtNoPos,
1414 [ + + ]: 40 : m = j + (int) t_group->nNumEndpoints; j < m; j++)
1415 : : {
1416 : 28 : pINChI->nTautomer[len++] = pCanonRank[(int) t_group_info->nEndpointAtomNumber[j]]; /* At[j] */
1417 : : }
1418 : : }
1419 : :
1420 : 7 : pINChI->lenTautomer = len;
1421 : 7 : pINChI_Aux->nNumberOfTGroups = n;
1422 : : }
1423 : : else
1424 : : {
1425 : 154 : pINChI->lenTautomer = 0;
1426 : 154 : pINChI_Aux->nNumberOfTGroups = 0;
1427 : :
1428 [ + - + + ]: 154 : if (t_group_info && ( ( t_group_info->tni.bNormalizationFlags & FLAG_NORM_CONSIDER_TAUT ) ||
1429 [ - + ]: 147 : (t_group_info->nNumIsotopicEndpoints > 1 &&
1430 [ # # ]: 0 : ( t_group_info->bTautFlagsDone & ( TG_FLAG_FOUND_ISOTOPIC_H_DONE | TG_FLAG_FOUND_ISOTOPIC_ATOM_DONE ) )) )
1431 : : ) /* djb-rwth: addressing LLVM warning */
1432 : : {
1433 : : /* only protons (re)moved or added */
1434 : 7 : pINChI->lenTautomer = 1;
1435 : 7 : pINChI->nTautomer[0] = 0;
1436 : : }
1437 : : }
1438 : :
1439 : : /* Number of H (excluding tautomeric) */
1440 [ + - ]: 161 : if (pCS->nNum_H)
1441 : : {
1442 [ + + ]: 971 : for (i = 0; i < num_atoms; i++)
1443 : : {
1444 : 810 : pINChI->nNum_H[i] = pCS->nNum_H[i];
1445 : : }
1446 : : }
1447 : :
1448 : :
1449 : : /* Number of fixed H (tautomeric H in non-tautomeric representation) */
1450 [ + - + + ]: 161 : if (pCS->nNum_H_fixed && !pINChI->lenTautomer)
1451 : : {
1452 [ + + ]: 906 : for (i = 0; i < num_atoms; i++)
1453 : : {
1454 : 759 : pINChI->nNum_H_fixed[i] = pCS->nNum_H_fixed[i];
1455 : 759 : pINChI->nNum_H[i] += pCS->nNum_H_fixed[i];
1456 : : }
1457 : : }
1458 : :
1459 : :
1460 : : /***********************************************************
1461 : : * Tautomeric group(s) numbering and symmetry;
1462 : : * should not depend on switching to rel. stereo numbering
1463 : : */
1464 [ + + + + ]: 161 : if (pINChI->lenTautomer && ( n = pINChI_Aux->nNumberOfTGroups ))
1465 : : {
1466 [ + + ]: 12 : pCanonOrdTaut = pCS->nLenCanonOrdStereoTaut > 0 ? pCS->nCanonOrdStereoTaut :
1467 [ + - ]: 5 : pCS->nLenCanonOrdTaut > 0 ? pCS->nCanonOrdTaut : NULL;
1468 : 7 : pConstitEquNumb = pINChI_Aux->nConstitEquTGroupNumbers;
1469 : 7 : pSymmRank = pCS->nSymmRankTaut;
1470 : :
1471 [ + - + - : 7 : if (pCanonOrdTaut && pSymmRank && pConstitEquNumb)
+ - ]
1472 : : {
1473 [ + + ]: 19 : for (i = 0; i < n; i++)
1474 : : {
1475 : 12 : pConstitEquNumb[i] = pSymmRank[pCanonOrdTaut[i]];
1476 : 12 : pSortOrd[i] = i;
1477 : : }
1478 : 7 : pCG->m_pn_RankForSort = pConstitEquNumb;
1479 : 7 : inchi_qsort( pCG, pSortOrd, n, sizeof( pSortOrd[0] ), CompRanksOrd );
1480 [ + + ]: 19 : for (i = 0, nMinOrd = pSortOrd[0], j = 1; j <= n; j++)
1481 : : {
1482 [ + + - + ]: 12 : if (j == n || pConstitEquNumb[pSortOrd[i]] != pConstitEquNumb[pSortOrd[j]])
1483 : : {
1484 : 7 : nMinOrd++; /* make is start from 1, not from zero */
1485 [ + + ]: 7 : if (j - i > 1)
1486 : : {
1487 : : /* found a sequence of more than one equivalent t-groups: i..j-1 */
1488 [ + + ]: 11 : while (i < j)
1489 : : {
1490 : 8 : pConstitEquNumb[pSortOrd[i++]] = nMinOrd;
1491 : : }
1492 : : }
1493 : : else
1494 : : {
1495 : 4 : pConstitEquNumb[pSortOrd[i++]] = 0;
1496 : : }
1497 : 7 : nMinOrd = pSortOrd[j]; /* at the end j == n */
1498 : : }
1499 : : }
1500 : : }
1501 : : }
1502 : :
1503 : :
1504 : : /* Allocate and fill Hill formula */
1505 : :
1506 : 161 : pINChI->szHillFormula = AllocateAndFillHillFormula( pINChI );
1507 : :
1508 [ - + ]: 161 : if (!pINChI->szHillFormula)
1509 : : {
1510 : 0 : nErrorCode = 0;
1511 : 0 : ret = CT_WRONG_FORMULA; /* CT_OUT_OF_RAM;*/ /* <BRKPT> */
1512 : 0 : pINChI->nErrorCode = pINChI_Aux->nErrorCode = ret;
1513 : 0 : goto exit_function;
1514 : : }
1515 : :
1516 : 161 : nStereoUnmarkMode = UnmarkAllUndefinedUnknownStereo( pINChI->Stereo, nUserMode );
1517 : :
1518 [ + + ]: 161 : if (nStereoUnmarkMode)
1519 : : {
1520 : 4 : pINChI->nFlags |=
1521 : : ( nStereoUnmarkMode & REQ_MODE_SC_IGN_ALL_UU ) ? INCHI_FLAG_SC_IGN_ALL_UU
1522 : 4 : : 0;
1523 : 4 : pINChI->nFlags |=
1524 : : ( nStereoUnmarkMode & REQ_MODE_SB_IGN_ALL_UU ) ? INCHI_FLAG_SB_IGN_ALL_UU
1525 : 4 : : 0;
1526 : :
1527 [ - + ]: 4 : if (( nStereoUnmarkMode & REQ_MODE_SC_IGN_ALL_UU ) ||
1528 [ # # ]: 0 : ( nStereoUnmarkMode & REQ_MODE_SB_IGN_ALL_UU ))
1529 : : {
1530 [ + - ]: 4 : if (!bNoWarnings)
1531 : : {
1532 : 4 : WarningMessage( pStrErrStruct, "Omitted undefined stereo" );
1533 : : }
1534 : : }
1535 : : }
1536 : :
1537 : : /*************************/
1538 : : /* Mark ambiguous stereo */
1539 : : /*************************/
1540 : :
1541 : 161 : MarkAmbiguousStereo( at, norm_at, 0 /* non-isotopic */, pCanonOrd,
1542 : : pCS->LinearCTStereoCarb, pCS->nLenLinearCTStereoCarb,
1543 : : pCS->LinearCTStereoDble, pCS->nLenLinearCTStereoDble );
1544 : :
1545 : :
1546 : : /************************************************************************
1547 : : *
1548 : : * Isotopic part
1549 : : */
1550 : :
1551 : : /* abs or rel stereo may establish one of two canonical numberings */
1552 : :
1553 [ + - - + ]: 161 : if (( pCS->nLenLinearCTIsotopicStereoCarb > 0 || pCS->nLenLinearCTIsotopicStereoDble > 0 ) &&
1554 [ # # ]: 0 : pCS->nLenCanonOrdIsotopicStereo > 0 &&
1555 [ # # # # ]: 0 : ( (pCS->LinearCTIsotopicStereoCarb && pCS->LinearCTIsotopicStereoCarbInv) ||
1556 [ # # # # ]: 0 : (pCS->LinearCTIsotopicStereoDble && pCS->LinearCTIsotopicStereoDbleInv) ) &&
1557 [ # # # # ]: 0 : pCS->nCanonOrdIsotopicStereo && pCS->nCanonOrdIsotopicStereoInv
1558 : : ) /* djb-rwth: addressing LLVM warning */
1559 : : {
1560 : : /* found isotopic stereo */
1561 : :
1562 : 0 : pCanonRank = pCanonRankAtoms;
1563 : 0 : pCanonOrd = pCS->nCanonOrdIsotopicStereo;
1564 : 0 : pCanonRankInv = pSortOrd;
1565 : 0 : pCanonOrdInv = pCS->nCanonOrdIsotopicStereoInv;
1566 : 0 : Stereo = pINChI->StereoIsotopic;
1567 : :
1568 [ # # ]: 0 : for (i = 0; i < num_at_tg; i++)
1569 : : {
1570 : 0 : pCanonRankInv[pCanonOrdInv[i]] =
1571 : 0 : pCanonRank[pCanonOrd[i]] = (AT_NUMB) ( i + 1 );
1572 : : }
1573 : :
1574 : :
1575 : : /********************************************************************/
1576 : : /* copy stereo bonds and stereo centers; compare Inv and Abs stereo */
1577 : : /********************************************************************/
1578 : :
1579 : 0 : nErrorCode = CopyLinearCTStereoToINChIStereo( Stereo,
1580 : : pCS->LinearCTIsotopicStereoCarb,
1581 : : pCS->nLenLinearCTIsotopicStereoCarb,
1582 : : pCS->LinearCTIsotopicStereoDble,
1583 : : pCS->nLenLinearCTIsotopicStereoDble,
1584 : : pCanonOrd, pCanonRank, at, 1 /* isotopic */,
1585 : : pCS->LinearCTIsotopicStereoCarbInv,
1586 : : pCS->LinearCTIsotopicStereoDbleInv,
1587 : : pCanonOrdInv, pCanonRankInv );
1588 : :
1589 : : /* djb-rwth: fixing oss-fuzz issue #68271 */
1590 [ # # ]: 0 : if (nErrorCode == 1)
1591 : : {
1592 : 0 : nErrorCode = 0;
1593 : 0 : ret = CT_OUT_OF_RAM; /* <BRKPT> */
1594 : 0 : pINChI->nErrorCode = pINChI_Aux->nErrorCode = CT_OUT_OF_RAM;
1595 : 0 : goto exit_function;
1596 : : }
1597 : :
1598 [ # # # # ]: 0 : if (Stereo->t_parityInv && Stereo->nNumberInv)
1599 : : {
1600 [ # # ]: 0 : if (nUserMode & REQ_MODE_RELATIVE_STEREO)
1601 : : {
1602 : 0 : pINChI->nFlags |= INCHI_FLAG_REL_STEREO;
1603 : : }
1604 : :
1605 [ # # ]: 0 : if (nUserMode & REQ_MODE_RACEMIC_STEREO)
1606 : : {
1607 : 0 : pINChI->nFlags |= INCHI_FLAG_RAC_STEREO;
1608 : : }
1609 : :
1610 [ # # ]: 0 : if (Stereo->nCompInv2Abs)
1611 : : {
1612 [ # # ]: 0 : if (Stereo->nCompInv2Abs == -1)
1613 : : {
1614 : : /* switch pointers so that the stereo becomes the smallest (relative) */
1615 : : /* flag Stereo->nCompInv2Abs == -1 will keep track of this exchange */
1616 : 0 : AT_NUMB *nNumberInv = Stereo->nNumberInv;
1617 : 0 : S_CHAR *t_parityInv = Stereo->t_parityInv;
1618 : 0 : Stereo->nNumberInv = Stereo->nNumber;
1619 : 0 : Stereo->t_parityInv = Stereo->t_parity;
1620 : 0 : Stereo->nNumber = nNumberInv;
1621 : 0 : Stereo->t_parity = t_parityInv;
1622 : 0 : switch_ptrs( &pCanonRank, &pCanonRankInv );
1623 : 0 : switch_ptrs( &pCanonOrd, &pCanonOrdInv );
1624 : 0 : bUseIsotopicNumberingInv = 1;
1625 : : }
1626 : : }
1627 : : }
1628 : :
1629 [ # # ]: 0 : for (i = 0; i < num_atoms; i++)
1630 : : {
1631 : 0 : pINChI_Aux->nIsotopicOrigAtNosInCanonOrdInv[i] = at[pCanonOrdInv[i]].orig_at_number;
1632 : 0 : pINChI_Aux->nIsotopicOrigAtNosInCanonOrd[i] = at[pCanonOrd[i]].orig_at_number;
1633 : : }
1634 : :
1635 [ # # ]: 0 : if (bUseIsotopicNumberingInv)
1636 : : {
1637 : 0 : switch_ptrs( &pCanonRank, &pCanonRankInv );
1638 : 0 : switch_ptrs( &pCanonOrd, &pCanonOrdInv );
1639 : 0 : memcpy(pCanonRank, pCanonRankInv, num_at_tg * sizeof(pCanonRank[0]));
1640 : 0 : memcpy(pCanonOrd, pCanonOrdInv, num_at_tg * sizeof(pCanonOrd[0]));
1641 : : }
1642 : :
1643 : 0 : pCanonRankInv = NULL;
1644 : 0 : pCanonOrdInv = NULL;
1645 : 0 : pOrigNosInCanonOrd = NULL;
1646 : : }
1647 : : else
1648 : : {
1649 : : /* no isotopic stereo */
1650 : :
1651 : 322 : pCanonOrd = pCS->nLenCanonOrdIsotopicStereo > 0 ? pCS->nCanonOrdIsotopicStereo
1652 [ - + - + ]: 161 : : pCS->nLenCanonOrdIsotopic > 0 ? pCS->nCanonOrdIsotopic
1653 : : : NULL;
1654 : 161 : pCanonRank = pCanonRankAtoms;
1655 : 161 : pOrigNosInCanonOrd = pINChI_Aux->nIsotopicOrigAtNosInCanonOrd;
1656 : :
1657 : : /* djb-rwth: fixing oss-fuzz issue #30496 */
1658 [ - + - - : 161 : if (pCanonOrd && pCanonRank && pOrigNosInCanonOrd)
- - ]
1659 : : {
1660 [ # # ]: 0 : for (i = 0; i < num_atoms; i++)
1661 : : {
1662 : : /* Fix13 -- out of bounds */
1663 : 0 : pCanonRank[pCanonOrd[i]] = (AT_NUMB) ( i + 1 );
1664 : 0 : pOrigNosInCanonOrd[i] = at[pCanonOrd[i]].orig_at_number;
1665 : : }
1666 [ # # ]: 0 : for (; i < num_at_tg; i++)
1667 : : {
1668 : : /* Fix13 -- out of bounds */
1669 : 0 : pCanonRank[pCanonOrd[i]] = (AT_NUMB) ( i + 1 );
1670 : : }
1671 : : }
1672 : : }
1673 : : /*pCanonOrdIso = pCanonOrd;*/
1674 : :
1675 : :
1676 : 161 : pConstitEquNumb = pINChI_Aux->nConstitEquIsotopicNumbers;
1677 : 161 : pSymmRank = pCS->nSymmRankIsotopic;
1678 : :
1679 [ - + - - : 161 : if (pCanonOrd && pCanonRank && pConstitEquNumb && pSymmRank)
- - - - ]
1680 : : {
1681 [ # # ]: 0 : for (i = 0; i < num_atoms; i++)
1682 : : {
1683 : 0 : pConstitEquNumb[i] = pSymmRank[pCanonOrd[i]];
1684 : 0 : pSortOrd[i] = i;
1685 : : }
1686 : :
1687 [ # # ]: 0 : for (; i < num_at_tg; i++)
1688 : : {
1689 : 0 : pSortOrd[i] = i;
1690 : : }
1691 : :
1692 : 0 : pCG->m_pn_RankForSort = pConstitEquNumb;
1693 : 0 : inchi_qsort( pCG, pSortOrd, num_atoms, sizeof( pSortOrd[0] ), CompRanksOrd );
1694 : :
1695 [ # # ]: 0 : for (i = 0, nMinOrd = pSortOrd[0], j = 1; j <= num_atoms; j++)
1696 : : {
1697 [ # # # # ]: 0 : if (j == num_atoms || pConstitEquNumb[pSortOrd[i]] != pConstitEquNumb[pSortOrd[j]])
1698 : : {
1699 : 0 : nMinOrd++;
1700 : :
1701 [ # # ]: 0 : if (j - i > 1)
1702 : : {
1703 : : /* found a sequence of equivalent atoms: i..j-1 */
1704 [ # # ]: 0 : while (i < j)
1705 : : {
1706 : 0 : pConstitEquNumb[pSortOrd[i++]] = nMinOrd;
1707 : : }
1708 : : }
1709 : : else
1710 : : {
1711 : 0 : pConstitEquNumb[pSortOrd[i++]] = 0; /* nMinOrd; */
1712 : : }
1713 : 0 : nMinOrd = pSortOrd[j];
1714 : : }
1715 : : }
1716 : : }
1717 : : else
1718 : : {
1719 : 161 : goto exit_function; /* no isotopic info available */
1720 : : }
1721 : :
1722 : :
1723 : : /* Isotopic atoms */
1724 : :
1725 : 0 : n = pINChI->nNumberOfIsotopicAtoms = pCS->nLenLinearCTIsotopic;
1726 : :
1727 [ # # ]: 0 : for (i = 0; i < n; i++)
1728 : : {
1729 : 0 : pINChI->IsotopicAtom[i].nAtomNumber = pCS->LinearCTIsotopic[i].at_num;
1730 : 0 : pINChI->IsotopicAtom[i].nIsoDifference = pCS->LinearCTIsotopic[i].iso_atw_diff;
1731 : 0 : pINChI->IsotopicAtom[i].nNum_H = pCS->LinearCTIsotopic[i].num_1H;
1732 : 0 : pINChI->IsotopicAtom[i].nNum_D = pCS->LinearCTIsotopic[i].num_D;
1733 : 0 : pINChI->IsotopicAtom[i].nNum_T = pCS->LinearCTIsotopic[i].num_T;
1734 : : }
1735 : :
1736 : : /* Isotopic tautomeric groups */
1737 : :
1738 : 0 : n = pINChI->nNumberOfIsotopicTGroups = pCS->nLenLinearCTIsotopicTautomer;
1739 : :
1740 [ # # ]: 0 : for (i = 0; i < n; i++)
1741 : : {
1742 : 0 : pINChI->IsotopicTGroup[i].nTGroupNumber = pCS->LinearCTIsotopicTautomer[i].tgroup_num;
1743 : 0 : pINChI->IsotopicTGroup[i].nNum_H = pCS->LinearCTIsotopicTautomer[i].num[2];
1744 : 0 : pINChI->IsotopicTGroup[i].nNum_D = pCS->LinearCTIsotopicTautomer[i].num[1];
1745 : 0 : pINChI->IsotopicTGroup[i].nNum_T = pCS->LinearCTIsotopicTautomer[i].num[0];
1746 : : }
1747 : :
1748 : : /* Atoms that may exchange isotopic H-atoms */
1749 : :
1750 [ # # # # ]: 0 : if (pCS->nExchgIsoH && pINChI->nPossibleLocationsOfIsotopicH)
1751 : : {
1752 [ # # ]: 0 : for (i = 0, j = 1; i < num_atoms; i++)
1753 : : {
1754 [ # # ]: 0 : if (pCS->nExchgIsoH[i])
1755 : : {
1756 : 0 : pINChI->nPossibleLocationsOfIsotopicH[j++] = (AT_NUMB) ( i + 1 ); /* canonical number */
1757 : : }
1758 : : }
1759 : 0 : pINChI->nPossibleLocationsOfIsotopicH[0] = (AT_NUMB) j; /* length including the 0th element */
1760 : : }
1761 : :
1762 [ # # ]: 0 : if ((nStereoUnmarkMode = UnmarkAllUndefinedUnknownStereo( pINChI->StereoIsotopic, nUserMode ))) /* djb-rwth: addressing LLVM warning */
1763 : : {
1764 : 0 : pINChI->nFlags |=
1765 : : ( nStereoUnmarkMode & REQ_MODE_SC_IGN_ALL_UU ) ? INCHI_FLAG_SC_IGN_ALL_ISO_UU
1766 : 0 : : 0;
1767 : 0 : pINChI->nFlags |=
1768 : : ( nStereoUnmarkMode & REQ_MODE_SB_IGN_ALL_UU ) ? INCHI_FLAG_SC_IGN_ALL_ISO_UU
1769 : 0 : : 0;
1770 [ # # ]: 0 : if (( nStereoUnmarkMode & REQ_MODE_SC_IGN_ALL_UU ) ||
1771 [ # # ]: 0 : ( nStereoUnmarkMode & REQ_MODE_SB_IGN_ALL_UU ))
1772 : : {
1773 [ # # ]: 0 : if (!bNoWarnings)
1774 : : {
1775 : 0 : WarningMessage( pStrErrStruct, "Omitted undefined stereo" );
1776 : : }
1777 : : }
1778 : : }
1779 : :
1780 : : /* Mark ambiguous stereo */
1781 : :
1782 : 0 : MarkAmbiguousStereo( at, norm_at, 1 /* isotopic */, pCanonOrd,
1783 : : pCS->LinearCTIsotopicStereoCarb, pCS->nLenLinearCTIsotopicStereoCarb,
1784 : : pCS->LinearCTIsotopicStereoDble, pCS->nLenLinearCTIsotopicStereoDble );
1785 : :
1786 : :
1787 : : /***********************************************************
1788 : : * Isotopic tautomeric group(s) numbering and symmetry;
1789 : : * should not depend on switching to rel. stereo numbering
1790 : : */
1791 : :
1792 [ # # ]: 0 : if (pINChI->lenTautomer &&
1793 [ # # ]: 0 : pINChI_Aux->nConstitEquIsotopicTGroupNumbers &&
1794 [ # # ]: 0 : pCS->nSymmRankIsotopicTaut &&
1795 [ # # # # : 0 : ( pCS->nLenLinearCTIsotopic || pCS->nLenLinearCTIsotopicTautomer ) &&
# # ]
1796 [ # # ]: 0 : t_group_info && t_group_info->num_t_groups > 0)
1797 : : {
1798 : :
1799 : : /* djb-rwth: removing redundant code */
1800 : :
1801 : 0 : pCanonOrdTaut =
1802 : 0 : pCS->nLenCanonOrdIsotopicStereoTaut > 0 ? ( n = pCS->nLenCanonOrdIsotopicStereoTaut, pCS->nCanonOrdIsotopicStereoTaut )
1803 [ # # # # ]: 0 : : pCS->nLenCanonOrdIsotopicTaut > 0 ? ( n = pCS->nLenCanonOrdIsotopicTaut, pCS->nCanonOrdIsotopicTaut )
1804 : 0 : : ( n = 0, (AT_RANK*) NULL );
1805 : :
1806 : 0 : pConstitEquNumb = pINChI_Aux->nConstitEquIsotopicTGroupNumbers;
1807 : :
1808 : 0 : pSymmRank = pCS->nSymmRankIsotopicTaut;
1809 : :
1810 [ # # # # : 0 : if (pCanonOrdTaut && pSymmRank && pConstitEquNumb && n > 0)
# # # # ]
1811 : : {
1812 [ # # ]: 0 : for (i = 0; i < n; i++)
1813 : : {
1814 : 0 : pConstitEquNumb[i] = pSymmRank[pCanonOrdTaut[i]];
1815 : 0 : pSortOrd[i] = i;
1816 : : }
1817 : :
1818 : 0 : pCG->m_pn_RankForSort = pConstitEquNumb;
1819 : 0 : inchi_qsort( pCG, pSortOrd, n, sizeof( pSortOrd[0] ), CompRanksOrd );
1820 [ # # ]: 0 : for (i = 0, nMinOrd = pSortOrd[0], j = 1; j <= n; j++)
1821 : : {
1822 [ # # # # ]: 0 : if (j == n || pConstitEquNumb[pSortOrd[i]] != pConstitEquNumb[pSortOrd[j]])
1823 : : {
1824 : 0 : nMinOrd++;
1825 [ # # ]: 0 : if (j - i > 1)
1826 : : {
1827 : : /* found a sequence of equivalent t-groups: i..j-1 */
1828 [ # # ]: 0 : while (i < j)
1829 : : {
1830 : 0 : pConstitEquNumb[pSortOrd[i++]] = nMinOrd;
1831 : : }
1832 : : }
1833 : : else
1834 : : {
1835 : 0 : pConstitEquNumb[pSortOrd[i++]] = 0; /* nMinOrd; */
1836 : : }
1837 : 0 : nMinOrd = pSortOrd[j]; /* at the end j = n */
1838 : : }
1839 : : }
1840 : : }
1841 : : }
1842 : :
1843 : :
1844 : 0 : exit_function:
1845 : :
1846 [ + - ]: 161 : if (pCanonRankAtoms)
1847 : : {
1848 [ + - ]: 161 : inchi_free( pCanonRankAtoms );
1849 : : }
1850 [ + - ]: 161 : if (pSortOrd)
1851 : : {
1852 [ + - ]: 161 : inchi_free( pSortOrd );
1853 : : }
1854 : :
1855 : 161 : pINChI->nErrorCode |= nErrorCode;
1856 : 161 : pINChI_Aux->nErrorCode |= nErrorCode;
1857 : :
1858 : 161 : return ret;
1859 : : }
|