1 /*  asngen.c
2 * ===========================================================================
3 *
4 *                            PUBLIC DOMAIN NOTICE
5 *               National Center for Biotechnology Information
6 *
7 *  This software/database is a "United States Government Work" under the
8 *  terms of the United States Copyright Act.  It was written as part of
9 *  the author's official duties as a United States Government employee and
10 *  thus cannot be copyrighted.  This software/database is freely available
11 *  to the public for use. The National Library of Medicine and the U.S.
12 *  Government have not placed any restriction on its use or reproduction.
13 *
14 *  Although all reasonable efforts have been taken to ensure the accuracy
15 *  and reliability of the software and data, the NLM and the U.S.
16 *  Government do not and cannot warrant the performance or results that
17 *  may be obtained by using this software or data. The NLM and the U.S.
18 *  Government disclaim all warranties, express or implied, including
19 *  warranties of performance, merchantability or fitness for any particular
20 *  purpose.
21 *
22 *  Please cite the author in any work or product based on this material.
23 *
24 * ===========================================================================
25 *
26 * File Name: asngen.c
27 *
28 * Author:  James Ostell
29 *
30 * Version Creation Date: 3/4/91
31 *
32 * $Revision: 6.3 $
33 *
34 * File Description:
35 *   General application interface routines for ASNlib
36 *      using these has the advantage that your routine will read binary
37 *        and print value messages with no changes
38 *      it has the disadvantage that you link both binary and text routines
39 *        whether you use them or not
40 *
41 * Modifications:
42 * --------------------------------------------------------------------------
43 * Date     Name        Description of modification
44 * -------  ----------  -----------------------------------------------------
45 * 3/4/91   Kans        Stricter typecasting for GNU C and C++
46 * 04-20-93 Schuler     LIBCALL calling convention
47 *
48 * $Log: asngen.c,v $
49 * Revision 6.3  2003/09/15 16:16:33  kans
50 * added AsnWriteEx, AsnTxtWriteEx, and AsnPrintStream
51 *
52 * Revision 6.2  1997/10/29 02:40:40  vakatov
53 * Type castings to pass through the C++ compiler
54 *
55 * Revision 6.1  1997/10/28 15:13:00  epstein
56 *  add AsnFindNthPieceOfObject
57 *
58 * Revision 6.0  1997/08/25 18:09:55  madden
59 * Revision changed to 6.0
60 *
61 * Revision 5.1  1996/12/03 21:43:48  vakatov
62 * Adopted for 32-bit MS-Windows DLLs
63 *
64  * Revision 5.0  1996/05/28  14:00:29  ostell
65  * Set to revision 5.0
66  *
67  * Revision 4.1  1996/01/03  22:59:49  ostell
68  * added ExpOptCheck on AsnReadVal()
69  *
70  * Revision 4.0  1995/07/26  13:47:38  ostell
71  * force revision to 4.0
72  *
73  * Revision 2.8  1995/05/15  18:38:28  ostell
74  * added Log line
75  *
76 *
77 * ==========================================================================
78 */
79 
80 #include "asnbuild.h"
81 
82 /*****************************************************************************
83 *
84 *   AsnReadId()
85 *   	generalized read ident
86 *
87 *****************************************************************************/
AsnReadId(AsnIoPtr aip,AsnModulePtr amp,AsnTypePtr atp)88 NLM_EXTERN AsnTypePtr LIBCALL  AsnReadId (AsnIoPtr aip, AsnModulePtr amp, AsnTypePtr atp)
89 
90 {
91 	if (aip->read_id)
92 		AsnIoErrorMsg(aip, 104, aip->linenumber);
93 	aip->read_id = TRUE;
94 
95     if (aip->type & ASNIO_TEXT)
96 		return AsnTxtReadId(aip, amp, atp);
97     else if (aip->type & ASNIO_BIN)
98 		return AsnBinReadId(aip, atp);
99 
100 	return NULL;
101 }
102 
103 /*****************************************************************************
104 *
105 *   AsnReadVal()
106 *   	generalized readvalue
107 *
108 *****************************************************************************/
AsnReadVal(AsnIoPtr aip,AsnTypePtr atp,DataValPtr vp)109 NLM_EXTERN Int2 LIBCALL AsnReadVal (AsnIoPtr aip, AsnTypePtr atp, DataValPtr vp)
110 
111 {
112 	Int2 retval = -1;
113 
114 	if (! aip->read_id)
115 		AsnIoErrorMsg(aip, 103, aip->linenumber);
116 	aip->read_id = FALSE;
117 
118 	if (aip->type & ASNIO_TEXT)
119 		retval = AsnTxtReadVal(aip, atp, vp);
120 	else if (aip->type & ASNIO_BIN)
121 		retval = AsnBinReadVal(aip, atp, vp);
122 
123 	if (aip->aeop != NULL)    /* exploring nodes */
124 		AsnCheckExpOpt(aip, atp, vp);
125 
126 	return retval;
127 }
128 
129 /*****************************************************************************
130 *
131 *   AsnWrite()
132 *   	generalized write value
133 *
134 *****************************************************************************/
AsnWrite(AsnIoPtr aip,AsnTypePtr atp,DataValPtr dvp)135 NLM_EXTERN Boolean LIBCALL AsnWrite (AsnIoPtr aip, AsnTypePtr atp, DataValPtr dvp)
136 
137 {
138 	Boolean retval = FALSE;
139 
140 	if (aip->aeop != NULL)    /* exploring nodes */
141 		AsnCheckExpOpt(aip, atp, dvp);
142 
143 	if (aip->type & ASNIO_TEXT)
144 		retval = AsnTxtWrite(aip, atp, dvp);
145 	else if (aip->type & ASNIO_BIN)
146 		retval = AsnBinWrite(aip, atp, dvp);
147 
148 	if (aip->io_failure)
149 		return FALSE;
150 	return retval;
151 }
152 
153 /*****************************************************************************
154 *
155 *   AsnWriteEx()
156 *   	specialized write value
157 *
158 *****************************************************************************/
AsnWriteEx(AsnIoPtr aip,AsnTypePtr atp,DataValPtr dvp,AsnStreamStringFunc stream)159 NLM_EXTERN Boolean LIBCALL AsnWriteEx (AsnIoPtr aip, AsnTypePtr atp, DataValPtr dvp, AsnStreamStringFunc stream)
160 
161 {
162 	Boolean retval = FALSE;
163 
164 	if (aip->aeop != NULL)
165 		AsnCheckExpOpt(aip, atp, dvp);
166 
167 	if (aip->type & ASNIO_TEXT)
168 		retval = AsnTxtWriteEx(aip, atp, dvp, stream);
169 	else if (aip->type & ASNIO_BIN)
170 		return FALSE;
171 
172 	if (aip->io_failure)
173 		return FALSE;
174 	return retval;
175 }
176 
177 /*****************************************************************************
178 *
179 *   AsnSkipValue(aip, atp)
180 *   	Assumes that a read id has just been done
181 *   	Assumes all values to be encountered are linked to atp
182 *   	will skip values until it returns to the former level
183 *   	returns TRUE if no errors
184 *       ends with a ReadVal()
185 *
186 *****************************************************************************/
AsnSkipValue(AsnIoPtr aip,AsnTypePtr atp)187 NLM_EXTERN Boolean LIBCALL AsnSkipValue (AsnIoPtr aip, AsnTypePtr atp)
188 
189 {
190 	Int2 level;
191 
192 	level = AsnGetLevel(aip);
193 	if (! AsnReadVal(aip, atp, NULL))
194 		return FALSE;
195 
196 	while (level < AsnGetLevel(aip))
197 	{
198 		if ((atp = AsnReadId(aip, NULL, atp)) == NULL)
199 			return FALSE;
200 		if (! AsnReadVal(aip, atp, NULL))
201 			return FALSE;
202 	}
203 	return TRUE;
204 }
205 
206 /*****************************************************************************
207 *
208 *   AsnOpenStruct(aip, atp, ptr)
209 *      write atp as a START_STRUCT
210 *
211 *****************************************************************************/
AsnOpenStruct(AsnIoPtr aip,AsnTypePtr atp,Pointer ptr)212 NLM_EXTERN Boolean LIBCALL AsnOpenStruct (AsnIoPtr aip, AsnTypePtr atp, Pointer ptr)
213 
214 {
215 	DataVal av;
216 	Boolean retval;
217 
218 	av.intvalue = START_STRUCT;
219 	if(aip->aeosp != NULL)
220 		aip->aeosp->the_struct = ptr;
221 	retval = AsnWrite(aip, atp, &av);
222 	if(aip->aeosp != NULL)
223 		aip->aeosp->the_struct = NULL;
224 	return retval;
225 }
226 
227 /*****************************************************************************
228 *
229 *   AsnCloseStruct(aip, atp, ptr)
230 *      writes an END_STRUCT for atp
231 *
232 *****************************************************************************/
AsnCloseStruct(AsnIoPtr aip,AsnTypePtr atp,Pointer ptr)233 NLM_EXTERN Boolean LIBCALL AsnCloseStruct (AsnIoPtr aip, AsnTypePtr atp, Pointer ptr)
234 
235 {
236 	DataVal av;
237     Int2 i;
238 	Boolean retval;
239 
240     i = aip->type_indent;
241     if (! i)
242 	{
243         AsnIoErrorMsg(aip, 20 );
244 		return FALSE;
245 	}
246 
247     i--;
248     while ((i) &&
249         (AsnFindBaseIsa(aip->typestack[i].type) == CHOICE_TYPE))
250         i--;
251     if (aip->typestack[i].type != atp)
252 	{
253         AsnIoErrorMsg(aip, 21, AsnErrGetTypeName(atp->name),
254 			AsnErrGetTypeName(aip->typestack[i].type->name));
255 		return FALSE;
256 	}
257 
258 	av.intvalue = END_STRUCT;
259 	if(aip->aeosp != NULL)
260 		aip->aeosp->the_struct = ptr;
261 	retval = AsnWrite(aip, atp, &av);
262 	if(aip->aeosp != NULL)
263 		aip->aeosp->the_struct = NULL;
264 	return retval;
265 }
266 
267 /*****************************************************************************
268 *
269 *   AsnWriteChoice(aip, atp, the_choice, the_value)
270 *
271 *****************************************************************************/
AsnWriteChoice(AsnIoPtr aip,AsnTypePtr atp,Int2 the_choice,DataValPtr the_value)272 NLM_EXTERN Boolean LIBCALL AsnWriteChoice (AsnIoPtr aip, AsnTypePtr atp, Int2 the_choice, DataValPtr the_value)
273 
274 {
275 	Boolean retval;
276 	DataVal av;
277 
278 	if (the_value == NULL)
279 	{
280 		av.ptrvalue = NULL;
281 		the_value = &av;
282 	}
283 	if(aip->aeosp != NULL)
284 		aip->aeosp->the_choice = the_choice;
285 	retval = AsnWrite(aip, atp, the_value);
286 	if(aip->aeosp != NULL)
287 		aip->aeosp->the_choice = NO_CHOICE_SET;
288 	return retval;
289 }
290 
291 /*****************************************************************************
292 *
293 *   Int2 AsnGetLevel(aip)
294 *       returns current level in parse stack
295 *       to traverse a struct (SEQUENCE, SET, SET OF, SEQUENCE OF)
296 *       atp = AsnReadId(aip, ...)    id for struct
297 *       level = AsnGetLevel(aip);    record level
298 *       AsnReadVal(aip, ...)         read open bracket to indent a level
299 *       while (AsnGetLevel(aip) != level)
300 *       {
301 *           AsnReadId()
302 *           AsnReadVal()
303 *       }
304 *       At this point you have read the close bracket for the struct
305 *
306 *****************************************************************************/
AsnGetLevel(AsnIoPtr aip)307 NLM_EXTERN Int2 LIBCALL AsnGetLevel (AsnIoPtr aip)
308 
309 {
310     return (Int2)aip->type_indent;
311 }
312 
313 /*****************************************************************************
314 *
315 *   AsnCheckExpOpt(aip, atp, dvp)
316 *   	see if atp is a node we are looking for
317 *       call user callback if it is
318 *
319 *****************************************************************************/
AsnCheckExpOpt(AsnIoPtr aip,AsnTypePtr atp,DataValPtr dvp)320 NLM_EXTERN void LIBCALL AsnCheckExpOpt (AsnIoPtr aip, AsnTypePtr atp, DataValPtr dvp)
321 
322 {
323 	AsnExpOptPtr aeop;
324 	AsnTypePtr base;
325 	Boolean got_one;
326 	Int2 i, j, isa, isa_end_struct;
327 
328 	aeop = aip->aeop;
329 	base = AsnFindBaseType(atp);
330 	while (aeop != NULL)
331 	{
332 		got_one = FALSE;
333 		if (aeop->numtypes == 1)    /* checking one type */
334 		{
335 			if ((aeop->types[0] == atp) ||
336 				(aeop->types[0] == base))
337 			{
338 				got_one = TRUE;
339 			}
340 		}
341 		else if (aeop->numtypes == 0)   /* checking all types */
342 			got_one = TRUE;
343 		else
344 		{
345 		  	if (aeop->types[aeop->numtypes - 1] == atp)
346 			{
347 				isa = base->type->isa;
348 
349 				isa_end_struct = 0;
350 				if ((isa == SEQ_TYPE) || (isa == SET_TYPE) ||
351 					 (isa == SEQOF_TYPE) || (isa == SETOF_TYPE))
352 				{
353 					 if (dvp->intvalue != START_STRUCT)
354 						isa_end_struct = 1;
355 				}
356 
357 				if ((Int2)aip->type_indent >= (aeop->numtypes - 1 - isa_end_struct))
358 				{
359 					if (isa_end_struct)
360 						i = aip->type_indent - 2;
361 					else
362 		 				i = aip->type_indent - 1;
363 		 			j = aeop->numtypes - 2;
364 					while ((j > 0) && (i > 0))
365 					{
366 						if (aip->typestack[i].type == aeop->types[j])
367 						{
368 							j--; i--;
369 						}
370 						else
371 							break;
372 					}
373 					if (! j)    /* got through it all */
374 					{
375 						if ((aip->typestack[i].type == aeop->types[0]) ||
376 							(AsnFindBaseType(aip->typestack[i].type) ==
377 								aeop->types[0]))
378 								got_one = TRUE;
379 					}
380 				}
381 			}
382 		}
383 
384 		if (got_one)   /* found it */
385 		{
386 			aip->aeosp->atp = atp;
387 			aip->aeosp->dvp = dvp;
388 			aip->aeosp->data = aeop->user_data;
389 			(* aeop->user_callback)(aip->aeosp);
390 		}
391 		aeop = aeop->next;
392 	}
393 	return;
394 }
395 
396 /*****************************************************************************
397 *
398 *   AsnExpOptNew(aip, path, ptr, func)
399 *
400 *****************************************************************************/
AsnExpOptNew(AsnIoPtr aip,CharPtr path,Pointer ptr,AsnExpOptFunc func)401 NLM_EXTERN AsnExpOptPtr LIBCALL AsnExpOptNew (AsnIoPtr aip, CharPtr path, Pointer ptr, AsnExpOptFunc func)   /* user supplied callback */
402 
403 {
404 	AsnExpOptPtr curr, prev;
405 	AsnTypePtr PNTR typeptr = NULL;
406 	Int2 typecount = 0;
407 
408 	if (path != NULL)     /* get type array */
409 	{
410 		typeptr = AsnTypePathFind(NULL, path, &typecount);
411 		if (typeptr == NULL)    /* path not found */
412 			return NULL;
413 	}
414 	curr = (AsnExpOptPtr) MemNew(sizeof(AsnExpOpt));
415 	curr->user_data = ptr;
416 	curr->user_callback = func;
417 	curr->types = typeptr;
418 	curr->numtypes = typecount;
419 	if (aip->aeop == NULL)   /* first one */
420 	{
421 		aip->aeop = curr;
422 		aip->aeosp = (AsnExpOptStructPtr) MemNew(sizeof(AsnExpOptStruct));
423 		aip->aeosp->aip = aip;
424 		aip->aeosp->the_choice = NO_CHOICE_SET;
425 	}
426 	else
427 	{
428 		prev = aip->aeop;
429 		while (prev->next != NULL)
430 			prev = prev->next;
431 		prev->next = curr;
432 	}
433 	return curr;
434 }
435 
436 /*****************************************************************************
437 *
438 *   AsnExpOptFree(aip, aeop)
439 *   	if aeop == NULL, free them all
440 *
441 *****************************************************************************/
AsnExpOptFree(AsnIoPtr aip,AsnExpOptPtr aeop)442 NLM_EXTERN AsnExpOptPtr LIBCALL AsnExpOptFree (AsnIoPtr aip, AsnExpOptPtr aeop)
443 
444 {
445 	AsnExpOptPtr curr, next, prev;
446 
447 	curr = aip->aeop;
448 	prev = NULL;
449 	while (curr != NULL)
450 	{
451 		if ((aeop == NULL) || (aeop == curr))
452 		{
453 			next = curr->next;
454 			if (prev != NULL)
455 				prev->next = next;
456 			else
457 				aip->aeop = next;
458 			MemFree(curr->types);
459 			MemFree(curr);
460 			curr = next;
461 		}
462 		else
463 		{
464 			prev = curr;
465 			curr = curr->next;
466 		}
467 	}
468 	if (prev == NULL)    /* nothing left */
469 		aip->aeosp = (AsnExpOptStructPtr) MemFree(aip->aeosp);   /* free the AsnExpOptStruct */
470 	return NULL;
471 }
472 
473 /*****************************************************************************
474 *
475 *   AsnNullValueMsg(aip, node)
476 *   	posts an error message when a NULL value is passed to the object
477 *   loaders for node.
478 *
479 *****************************************************************************/
AsnNullValueMsg(AsnIoPtr aip,AsnTypePtr node)480 NLM_EXTERN void LIBCALL AsnNullValueMsg (AsnIoPtr aip, AsnTypePtr node)
481 
482 {
483 	char * tmpbuf;
484 	CharPtr str;
485 
486 	tmpbuf = (char*) malloc(512);   /* temp. local buffer for mswindows */
487 	str = StringMove(tmpbuf, "NULL value passed to object loader for ");
488 	str = AsnTypeDumpStack(str, aip);
489 	if (node != NULL)
490 	{
491 		if (*(str - 1) == '>')    /* already read or written */
492 		{
493 			while (*str != '<')
494 				str--;
495 		}
496 		else
497 		{
498 			*str = '.';
499 			str++;
500 		}
501 		StringMove(str, node->name);
502 	}
503 	ErrPost(CTX_NCBIOBJ, 1, tmpbuf);
504 	free(tmpbuf);
505 	return;
506 }
507 
508 
509 
510 typedef struct {
511     Int4 count;
512     Pointer val;
513 } StructInfo;
514 
GetNth(AsnExpOptStructPtr aeosp)515 static void LIBCALLBACK GetNth(AsnExpOptStructPtr aeosp)
516 {
517 	StructInfo *sp;
518 
519         if (aeosp->dvp->intvalue != START_STRUCT) return;
520 	sp = (StructInfo *) aeosp->data;
521 	if (sp->count-- == 1)
522 	    sp->val = (Pointer) aeosp->the_struct;
523 }
524 
525 /* Finds the Nth occurrence of any low-level ASN.1 object within a higher
526    level object for which an ASN.1 Write function exists.  The string
527    parameter must identify the low-level object for which the search is
528    being performed.
529 
530    Note that this function can be used to obtain pieces of an object in an
531    object-oriented "method", rather than using the native method of
532    traversing pointers to fetch the desired piece.  However, note that
533    this technique is very inefficient since the entire structure must be
534    traversed to obtain each component. */
535 NLM_EXTERN VoidPtr LIBCALL
AsnFindNthPieceOfObject(AsnWriteFunc wfunc,Pointer datum,CharPtr string,Int4 n)536 AsnFindNthPieceOfObject(AsnWriteFunc wfunc, Pointer datum, CharPtr string, Int4 n)
537 {
538   AsnIoPtr aip;
539   StructInfo si;
540   AsnExpOptPtr aeop;
541 
542   aip = AsnIoNullOpen();
543   si.count = n;
544   si.val = NULL;
545   aeop = AsnExpOptNew(aip, string, (Pointer)&si, GetNth);
546   wfunc(datum, aip, NULL);
547   AsnIoClose(aip);
548   return si.val;
549 }
550 
551