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