1 /*  ncbibs.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:  ncbibs.c
27 *
28 * Author:  Jim Ostell
29 *
30 * Version Creation Date:  3/4/91
31 *
32 * $Revision: 6.8 $
33 *
34 * File Description:
35 *   ByteStore functions
36 *      NOTE: increasing BS_MAXALLOC will require changing len, and
37 * 		   len_avail to Int4 (ncbibs.h)
38 *
39 *   This version needs the following enhancements:
40 *   1) a BSCompact function to pack a fragmented ByteStore
41 *   2) use made of MIN_BSALLOC to make all allocated space at
42 *      least MIN_BSALLOC long, so it would be possible to have len_avail
43 *      bigger than len at internal BSUnits as well as at the end.  This
44 *      will make insertion and appending of small amounts much more
45 *      efficient.
46 *
47 * Modifications:
48 * --------------------------------------------------------------------------
49 * Date     Name        Description of modification
50 * -------  ----------  -----------------------------------------------------
51 *
52 * ==========================================================================
53 */
54 
55 #include <ncbi.h>
56 #include <ncbiwin.h>
57 
58          /* maximum size allocated for BSUnit.str */
59 #define MAX_BSALLOC 32700
60          /* minimum size block to allocate except on new */
61 #define MIN_BSALLOC 1024
62 
63 #ifdef MSC_VIRT
64 extern Nlm_Boolean wrote_to_handle;  /* needed by Microsoft DOS Virtual mem */
65 #undef MAX_BSALLOC					 /* bad with big blocks */
66 #define MAX_BSALLOC 10000
67 #endif
68 
69 /*****************************************************************************
70 *
71 *   Pointer Nlm_BSMerge(bsp, dest)
72 *      if dest == NULL, allocates storage for merge and returns pointer to it
73 *
74 *****************************************************************************/
Nlm_BSMerge(Nlm_ByteStorePtr bsp,Nlm_VoidPtr dest)75 NLM_EXTERN Nlm_VoidPtr LIBCALL  Nlm_BSMerge (Nlm_ByteStorePtr bsp, Nlm_VoidPtr dest)
76 
77 {
78 	Nlm_BytePtr tmp, from;
79 	Nlm_BSUnitPtr bsup;
80     size_t size;
81 
82 	if (bsp == NULL)
83 		return NULL;
84 
85     size = Nlm_BSLen(bsp) + 1;
86     if (size > SIZE_MAX) {
87 		ErrPostEx(SEV_ERROR, 0, 0, "size[%u] is bigger then SIZE_MAX[%u]",
88 			size, SIZE_MAX);
89         /* should post an error here */
90         return NULL;
91     }
92 
93 	if (dest == NULL)         /* allocate storage with room for null at end */
94 	{
95 		dest = Nlm_MemNew(size);
96 		if (dest == NULL) return dest;
97 	}
98 
99 	tmp = (Nlm_BytePtr) dest;
100 	bsup = bsp->chain;
101 
102 	while (bsup != NULL)
103 	{
104 		from = (Nlm_BytePtr) Nlm_HandLock(bsup->str);
105 		Nlm_MemCopy(tmp, from, bsup->len);
106 		Nlm_HandUnlock(bsup->str);
107 		tmp += bsup->len;
108 		bsup = bsup->next;
109 	}
110 
111 	return dest;
112 }
113 
114 /*****************************************************************************
115 *
116 *   ByteStorePtr Nlm_BSNew(len)
117 *   	creates a big enough bytestore for len
118 *
119 *****************************************************************************/
Nlm_BSNew(Nlm_Int4 len)120 NLM_EXTERN Nlm_ByteStorePtr LIBCALL Nlm_BSNew (Nlm_Int4 len)
121 
122 {
123 	Nlm_ByteStorePtr bsp;
124 	Nlm_Int4 added;
125 
126 	bsp = (Nlm_ByteStorePtr) Nlm_MemNew(sizeof(ByteStore));
127 	if (bsp == NULL)
128 		return NULL;
129 
130 	added = Nlm_BSAdd(bsp, len, FALSE);
131 	if (added < len)
132 		bsp = Nlm_BSFree(bsp);
133 	return bsp;
134 }
135 
136 /*****************************************************************************
137 *
138 *   Int4 BSAdd(bsp, len, use_min_size)
139 *   	adds len bytes BEFORE current bsp->seekptr
140 *       bsp->seekptr returned pointing at first added byte
141 *   	returns bytes added
142 *       if (use_min_size) then does not add anything smaller than MIN_BSALLOC
143 *
144 *****************************************************************************/
Nlm_BSAdd(Nlm_ByteStorePtr bsp,Nlm_Int4 len,Nlm_Boolean use_min_size)145 NLM_EXTERN Nlm_Int4 LIBCALL Nlm_BSAdd (Nlm_ByteStorePtr bsp, Nlm_Int4 len, Nlm_Boolean use_min_size)
146 
147 {
148 	Nlm_BSUnitPtr bsup,      /* current bsunit */
149 		          ccbsup,    /* bsp->curchain */
150 				lastbsup,    /* bsunit after added section  */
151 				prevbsup;    /* bsunit before added section */
152 	Nlm_BytePtr to, from;
153 	Nlm_Int4 added = 0,
154 		      tlen;
155 	Nlm_Handle thand;
156 
157 	if ((bsp == NULL) || (len == 0))
158 		return added;
159 
160 	lastbsup = NULL;
161 	prevbsup = NULL;
162 	ccbsup = bsp->curchain;
163 
164 	if (bsp->chain != NULL)        /* add or insert in exisiting chain */
165 	{
166 		if (bsp->seekptr == bsp->chain_offset)   /* before start of block */
167 		{
168 			lastbsup = ccbsup;       /* it comes after */
169 			if (bsp->seekptr != 0)          /* something before it */
170 			{
171 				prevbsup = bsp->chain;
172 				while (prevbsup->next != ccbsup)
173 					prevbsup = prevbsup->next;
174 			}
175 		}										 /* at very end of data */
176 		else if (bsp->seekptr == (bsp->chain_offset + ccbsup->len))
177 		{
178 			prevbsup = ccbsup; /* JK */
179 		}										 /* after all blocks */
180 		else if (bsp->seekptr >= (bsp->chain_offset + ccbsup->len_avail))
181 		{
182 			prevbsup = ccbsup;
183 		}
184 		else                /* split a bsunit */
185 		{
186 			bsup = (Nlm_BSUnitPtr) Nlm_MemNew(sizeof(Nlm_BSUnit));
187 			if (bsup == NULL) return added;
188 			if (bsp->chain_offset != 0)          /* not first BSUnit */
189 			{
190 				prevbsup = bsp->chain;
191 				while (prevbsup->next != ccbsup)
192 					prevbsup = prevbsup->next;
193 				prevbsup->next = bsup;      /* insert new bsunit */
194 			}
195 			else
196 			    bsp->chain = bsup;
197 			bsup->next = ccbsup;
198 			tlen = bsp->seekptr - bsp->chain_offset;  /* len of first half */
199 			bsup->str = Nlm_HandNew((size_t) tlen);
200 			if (bsup->str == NULL) return added;
201 			bsup->len = (Nlm_Int2) tlen;
202 			bsup->len_avail = (Nlm_Int2) tlen;
203 			to = (Nlm_BytePtr) Nlm_HandLock(bsup->str);
204 			thand = ccbsup->str;
205 			from = (Nlm_BytePtr) Nlm_HandLock(thand);
206 			Nlm_MemCopy(to, from, (size_t) tlen);
207 #ifdef MSC_VIRT
208 			wrote_to_handle = TRUE;
209 #endif
210 			Nlm_HandUnlock(bsup->str);
211 			from += tlen;      /* point past copied region */
212 			tlen = ccbsup->len - tlen;    /* the last half */
213 			ccbsup->len = (Nlm_Int2) tlen;
214 			ccbsup->len_avail = (Nlm_Int2) tlen;
215 			ccbsup->str = Nlm_HandNew((size_t) tlen);
216 			if (ccbsup->str == NULL) return added;
217 			to = (Nlm_BytePtr) Nlm_HandLock(ccbsup->str);
218 			Nlm_MemCopy(to, from, (size_t) tlen);
219 #ifdef MSC_VIRT
220 	wrote_to_handle = TRUE;
221 #endif
222 			Nlm_HandUnlock(ccbsup->str);
223 			Nlm_HandUnlock(thand);
224 			Nlm_HandFree(thand);
225 			prevbsup = bsup;
226 			lastbsup = ccbsup;
227 		}
228 	}
229 
230 	ccbsup = NULL;
231 	bsup = NULL;
232 	while (len)
233 	{
234 		bsup = (Nlm_BSUnitPtr) Nlm_MemNew(sizeof(Nlm_BSUnit));
235 		if (bsup == NULL)
236 			return added;
237 		if (len < MAX_BSALLOC)
238 
239 		{
240 			if ((use_min_size) && (len < MIN_BSALLOC))
241 				len = MIN_BSALLOC;
242 			tlen = len;
243 		}
244 		else
245 			tlen = MAX_BSALLOC;
246 		bsup->str = Nlm_HandNew((size_t)tlen);
247 		if (bsup->str == NULL)
248 		{
249 			Nlm_MemFree(bsup);
250 			return added;
251 		}
252 		bsup->len_avail = (Nlm_Int2) tlen;
253 		if (prevbsup == NULL)
254 			bsp->chain = bsup;
255 		else
256 			prevbsup->next = bsup;
257 		if (ccbsup == NULL)
258 			ccbsup = bsup;          /* current position */
259 		prevbsup = bsup;
260 		len -= tlen;
261 		added += tlen;
262 	}
263 	if (bsup != NULL)
264 		bsup->next = lastbsup;
265 	bsp->curchain = ccbsup;
266 	bsp->chain_offset = bsp->seekptr;   /* added block starts at seekptr */
267 	return added;
268 }
269 
270 /*****************************************************************************
271 *
272 *   Int4 BSDelete(bsp, len)
273 *   	deletes len bytes starting at current bsp->seekptr
274 *   	returns bytes deleted
275 *
276 *****************************************************************************/
Nlm_BSDelete(Nlm_ByteStorePtr bsp,Nlm_Int4 len)277 NLM_EXTERN Nlm_Int4 LIBCALL  Nlm_BSDelete (Nlm_ByteStorePtr bsp, Nlm_Int4 len)
278 
279 {
280 	Nlm_BSUnitPtr bsup,      /* current bsunit */
281 		          ccbsup,    /* bsp->curchain */
282 				nextbsup,    /* bsunit after added section  */
283 				prevbsup;    /* bsunit before added section */
284 	Nlm_BytePtr to, from;
285 	Nlm_Int4 added = 0,
286 		      offset,
287 		      tlen,
288 			  start,
289 			  save;
290 	Nlm_Handle thand;
291 
292 	if ((bsp == NULL) || (len == 0) || (bsp->chain == NULL) ||
293 		(bsp->seekptr >= bsp->totlen))
294 		return added;
295 
296 	if ((bsp->seekptr + len) > bsp->totlen)   /* deleting too much */
297 		len = bsp->totlen - bsp->seekptr;
298 
299 	nextbsup = NULL;
300 	ccbsup = bsp->curchain;
301 	start = bsp->chain_offset;
302 	offset = bsp->seekptr - bsp->chain_offset;
303 	if (offset)           /* will leave part of first bsunit */
304 		prevbsup = ccbsup;
305 	else if (bsp->chain_offset != 0)          /* something before this bsunit */
306 	{
307 		prevbsup = bsp->chain;
308 		while (prevbsup->next != ccbsup)
309 			prevbsup = prevbsup->next;
310 	}
311 	else
312 		prevbsup = NULL;       /* will remove beginning of first bsunit */
313 
314 	bsup = ccbsup;
315 	while (len)
316 	{
317 		nextbsup = bsup->next;
318 		tlen = bsup->len - offset;
319 		if (tlen > len)
320 			tlen = len;			 /* will remove tlen bytes from this BSUnit*/
321 		save = bsup->len - tlen;
322 		if (save)    /* some bytes left after delete */
323 		{
324 			thand = bsup->str;
325 			bsup->str = Nlm_HandNew((size_t) save);
326 			if (bsup->str == NULL) return added;
327 			bsup->len = (Nlm_Int2) save;
328 			bsup->len_avail = (Nlm_Int2) save;
329 			to = (Nlm_BytePtr) Nlm_HandLock(bsup->str);
330 			from = (Nlm_BytePtr) Nlm_HandLock(thand);
331 			if (offset)         /* get the beginning */
332 				Nlm_MemCopy(to, from, (size_t) offset);
333 			save -= offset;
334 			if (save)           /* save end */
335 				Nlm_MemCopy((to + offset), (from + (offset + tlen)), (size_t)save);
336 			Nlm_HandUnlock(thand);
337 			Nlm_HandFree(thand);
338 #ifdef MSC_VIRT
339 	wrote_to_handle = TRUE;
340 #endif
341 			Nlm_HandUnlock(bsup->str);
342 			if (tlen < len)
343 				bsup = nextbsup;
344 		}
345 		else                    /* delete the whole thing */
346 		{
347 			Nlm_HandFree(bsup->str);
348 			Nlm_MemFree(bsup);
349 			bsup = nextbsup;
350 		}
351 		offset = 0;
352 		len -= tlen;
353 		added += tlen;
354 	}
355 	if ((bsup != prevbsup) ||   /* break in chain, rejoin it */
356              ((bsup == NULL) && (prevbsup == NULL)))   /* chain gone */
357 	{
358 		if (prevbsup == NULL)
359 			bsp->chain = bsup;
360 		else
361 			prevbsup->next = bsup;
362 	}
363 	bsp->curchain = bsup;
364 	bsp->totlen -= added;
365 	if (bsp->totlen)
366 	{
367 		offset = bsp->seekptr;
368 		start = 0;
369 		bsup = bsp->chain;
370 		while (offset >= (start + bsup->len_avail))
371 		{
372 			if (bsup->next == NULL)    /* EOF */
373 				offset = 0;            /* stop loop */
374 			else
375 			{
376 				start += bsup->len;
377 				bsup = bsup->next;
378 			}
379 		}
380 		bsp->curchain = bsup;
381 		bsp->chain_offset = start;
382 	}
383 	else
384 	{
385 		bsp->chain_offset = 0;
386 		bsp->curchain = bsp->chain;
387 	}
388 	return added;
389 }
390 
391 /*****************************************************************************
392 *
393 *   Nlm_Int4 Nlm_BSTell(bsp)
394 *
395 *****************************************************************************/
Nlm_BSTell(Nlm_ByteStorePtr bsp)396 NLM_EXTERN Nlm_Int4 LIBCALL  Nlm_BSTell (Nlm_ByteStorePtr bsp)
397 
398 {
399 	if (bsp == NULL)
400 		return 0L;
401 
402 	return bsp->seekptr;
403 }
404 
405 /*****************************************************************************
406 *
407 *   Int2 Nlm_BSSeek(bsp, offset, origin)
408 *   	seeks as fseek()
409 *   	trys to lock a BSUnit at that seek position
410 *
411 *****************************************************************************/
Nlm_BSSeek(Nlm_ByteStorePtr bsp,Nlm_Int4 offset,Nlm_Int2 origin)412 NLM_EXTERN Nlm_Int2 LIBCALL  Nlm_BSSeek (Nlm_ByteStorePtr bsp, Nlm_Int4 offset, Nlm_Int2 origin)
413 
414 {
415 	Nlm_Int4 sp, start = 0;
416 	Nlm_BSUnitPtr bsup;
417 	Nlm_Boolean done;
418 
419 	if (bsp == NULL)
420 		return 1;
421 	if (bsp->chain == NULL)
422 		return 1;
423 
424 	sp = bsp->seekptr;
425 
426 	switch (origin)
427 	{
428 		case SEEK_SET:
429 			if ((offset > bsp->totlen) || (offset < 0))
430 				return 1;
431 			sp = offset;
432 			break;
433 		case SEEK_CUR:
434 			if (((sp + offset) > bsp->totlen) ||
435 				((sp + offset) < 0 ))
436 				return 1;
437 			sp += offset;
438 			break;
439 		case SEEK_END:
440 			if ((ABS(offset) > bsp->totlen) || (offset > 0))
441 				return 1;
442 			sp = bsp->totlen + offset;
443 			break;
444 		default:
445 			return 1;
446 	}
447 
448     if (sp == bsp->seekptr)     /* already in right position */
449         return 0;
450 
451 	bsp->seekptr = sp;
452 	                             /* if a valid seek, lock the right BSUnit */
453 	bsup = bsp->curchain;
454 
455 	if (sp == bsp->totlen)    /* seek to EOF */
456 	{
457 		if (sp > (bsp->chain_offset + bsup->len_avail))
458 		{
459 			start = bsp->chain_offset;
460 			while (sp > (start + bsup->len_avail))
461 			{
462 				start += bsup->len;
463 				bsup = bsup->next;
464 			}
465 		}
466 	}
467 	else if ((sp < bsp->chain_offset) ||
468 		(sp >= (bsp->chain_offset + bsup->len)))
469 	{
470 		if (sp < bsp->chain_offset)
471 		{
472 			bsup = bsp->chain;
473 			start = 0;
474 		}
475 		else
476 		{
477 			start = bsp->chain_offset + bsup->len;
478 			bsup = bsup->next;
479 		}
480 		done = FALSE;
481 		while (! done)
482 		{
483 			if ((start + bsup->len) > sp)
484 				done = TRUE;
485 			else
486 			{
487 				start += bsup->len;
488 				bsup = bsup->next;
489 			}
490 		}
491 	}
492 	if (bsup != bsp->curchain)
493 	{
494 		bsp->chain_offset = start;
495 		bsp->curchain = bsup;
496 	}
497 	return 0;
498 }
499 /*****************************************************************************
500 *
501 *   Int4 Nlm_BSLen(bsp)
502 *      gives cumulative length of strings in store (not counting \0)
503 *
504 *****************************************************************************/
Nlm_BSLen(Nlm_ByteStorePtr bsp)505 NLM_EXTERN Nlm_Int4 LIBCALL  Nlm_BSLen (Nlm_ByteStorePtr bsp)
506 
507 {
508 	if (bsp == NULL)
509 		return 0L;
510 
511 	return bsp->totlen;
512 }
513 
514 /*****************************************************************************
515 *
516 *   Int2 BSPutByte(bsp, value)
517 *       - returns value on success, EOF on failure
518 *       - BSPutByte(bsp, EOF) truncates at seekptr
519 *
520 *****************************************************************************/
Nlm_BSPutByte(Nlm_ByteStorePtr bsp,Nlm_Int2 value)521 NLM_EXTERN Nlm_Int2 LIBCALL  Nlm_BSPutByte (Nlm_ByteStorePtr bsp, Nlm_Int2 value)
522 
523 {
524 	Nlm_Uint1 b;
525     if (value == EOF)
526         Nlm_BSDelete(bsp, INT4_MAX);
527     else {
528     	b = (Nlm_Uint1) value;
529         if (Nlm_BSWrite(bsp, (Nlm_VoidPtr)&b, 1) == 0)
530             return EOF;
531     }
532     return value;
533 }
534 
535 /*****************************************************************************
536 *
537 *   Int4 BSWrite(bsp, ptr, len)
538 *   	returns bytes written from ptr to bsp
539 *       writes from current seekptr position
540 *       seekptr left pointing after last byte written
541 *       allocates storage if needed
542 *       writes over any data already there
543 *
544 *****************************************************************************/
Nlm_BSWrite(Nlm_ByteStorePtr bsp,Nlm_VoidPtr ptr,Nlm_Int4 len)545 NLM_EXTERN Nlm_Int4 LIBCALL  Nlm_BSWrite (Nlm_ByteStorePtr bsp, Nlm_VoidPtr ptr, Nlm_Int4 len)
546 
547 {
548 	Nlm_BytePtr from, to;
549 	Nlm_BSUnitPtr bsup;
550 	Nlm_Int4 tlen, added = 0, offset, start, diff;
551 
552 	if ((bsp == NULL) || (len <= 0))
553 		return added;
554 
555 	bsup = bsp->curchain;
556 	from = (Nlm_BytePtr) ptr;
557 	offset = bsp->seekptr - bsp->chain_offset;
558 	start = bsp->chain_offset;
559 
560 
561 
562  	while (len)
563 	{
564 
565 		if (bsup == NULL)
566 			tlen = 0;
567 		else
568 			tlen = bsup->len_avail - offset;
569 		if (len < tlen)
570 			tlen = len;
571 		if (! tlen)       /* out of space */
572 		{
573 
574 			if (Nlm_BSAdd(bsp, len, TRUE) < len)
575 				return added;
576 			bsup = bsp->curchain;
577 			offset = bsp->seekptr - bsp->chain_offset;
578 			tlen = bsup->len_avail;
579 
580 			if (len < tlen)
581 
582 				tlen = len;
583 		}
584 		else
585 		{
586 			bsp->chain_offset = start;
587 			bsp->curchain = bsup;
588 		}
589 		to = (Nlm_BytePtr)Nlm_HandLock(bsup->str) + offset;
590 		Nlm_MemCopy(to, from, (size_t) tlen);
591 #ifdef MSC_VIRT
592 	wrote_to_handle = TRUE;
593 #endif
594 		Nlm_HandUnlock(bsup->str);
595 		if (bsup->len < (Nlm_Int2)(tlen + offset))   /* added more to this bsunit */
596 		{
597 			diff = (tlen + offset) - bsup->len;
598 			bsp->totlen += diff;
599 			bsup->len += (Nlm_Int2) diff;
600 
601 		}
602 		offset = 0;        /* only offset on first one */
603 		len -= tlen;
604 		bsp->seekptr += tlen;
605 		start += bsup->len;
606 		added += tlen;
607 		from += tlen;
608 		if (len)
609 			bsup = bsup->next;
610 	}
611 	                 /* pointing past end of this BSunit */
612 
613 	if ((bsp->seekptr - bsp->chain_offset) >= bsup->len_avail)
614 	{
615 		if (bsup->next != NULL)      /* not end of space */
616 		{
617 			bsp->curchain = bsup->next;
618 			bsp->chain_offset += bsup->len;  /* should = len_avail */
619 		}
620 	}
621 	return added;
622 }
623 /*****************************************************************************
624 *
625 *   Int4 BSRead(bsp, ptr, len)
626 *   	returns bytes read from bsp to ptr
627 *       reads from current seekptr position
628 *       seekptr left pointing after last byte read
629 *
630 *****************************************************************************/
Nlm_BSRead(Nlm_ByteStorePtr bsp,Nlm_VoidPtr ptr,Nlm_Int4 len)631 NLM_EXTERN Nlm_Int4 LIBCALL  Nlm_BSRead (Nlm_ByteStorePtr bsp, Nlm_VoidPtr ptr, Nlm_Int4 len)
632 
633 {
634 	Nlm_BytePtr from, to;
635 	Nlm_BSUnitPtr bsup;
636 	Nlm_Int4 tlen, added = 0, offset, start;
637 
638 	if ((bsp == NULL) || (len <= 0))
639 		return added;
640 
641 	bsup = bsp->curchain;
642 	to = (Nlm_BytePtr) ptr;
643 	offset = bsp->seekptr - bsp->chain_offset;
644 	start = bsp->chain_offset;
645 
646  	while (len)
647 	{
648 		if (bsup == NULL)
649 			return added;
650 		tlen = bsup->len - offset;
651 		if (len < tlen)
652 			tlen = len;
653 		if (! tlen)       /* out of data */
654 			return added;
655 		bsp->chain_offset = start;
656 		from = (Nlm_BytePtr)Nlm_HandLock(bsup->str) + offset;
657 		Nlm_MemCopy(to, from, (size_t) tlen);
658 		Nlm_HandUnlock(bsup->str);
659 		offset = 0;        /* only offset on first one */
660 		len -= tlen;
661 		bsp->seekptr += tlen;
662 		bsp->curchain = bsup;
663 		start += bsup->len;
664 		added += tlen;
665 		to += tlen;
666 		if (len)
667 			bsup = bsup->next;
668 	}                                    /*** end of this bsunit? **/
669 	if ((bsp->seekptr - bsp->chain_offset) == bsup->len)
670 	{
671 		if (bsup->next != NULL)    /* not EOF */
672 		{
673 			bsp->curchain = bsup->next;
674 			bsp->chain_offset += bsup->len;
675 		}
676 	}
677 	return added;
678 }
679 
680 /*****************************************************************************
681 *
682 *   Int2 BSGetByte(bsp)
683 *      reads a byte and increments the seekptr
684 *      returns EOF on End-Of-BS or error
685 *
686 *****************************************************************************/
Nlm_BSGetByte(Nlm_ByteStorePtr bsp)687 NLM_EXTERN Nlm_Int2 LIBCALL  Nlm_BSGetByte (Nlm_ByteStorePtr bsp)
688 
689 {
690 	Nlm_Int2 retval;
691 	Nlm_BytePtr ptr;
692 	Nlm_Int4 diff;
693 	Nlm_BSUnitPtr bsup;
694 
695 	if ((bsp == NULL) || (bsp->totlen == 0) || (bsp->seekptr == bsp->totlen))
696 		return EOF;      /* EOF */
697 
698 	diff = bsp->seekptr - bsp->chain_offset;
699 	bsup = bsp->curchain;
700 	ptr = (Nlm_BytePtr) Nlm_HandLock(bsup->str);
701 	retval = (Nlm_Int2) *(ptr + diff);
702 	Nlm_HandUnlock(bsup->str);
703 
704 	bsp->seekptr++;
705 	diff++;
706 	if (diff == bsup->len)
707 	{
708 		if (bsp->seekptr != bsp->totlen)    /* not EOF */
709 		{
710 			bsp->curchain = bsup->next;
711 			bsp->chain_offset += bsup->len;
712 		}
713 	}
714 	return retval;
715 }
716 
717 /*****************************************************************************
718 *
719 *   Int4 BSInsert(bsp, ptr, len)
720 *   	returns bytes written from ptr into bsp
721 *       writes from current seekptr position
722 *       seekptr left pointing after last byte written
723 *       allocates storage if needed
724 *       inserts data BEFORE seekptr
725 *
726 *****************************************************************************/
Nlm_BSInsert(Nlm_ByteStorePtr bsp,Nlm_VoidPtr ptr,Nlm_Int4 len)727 NLM_EXTERN Nlm_Int4 LIBCALL  Nlm_BSInsert (Nlm_ByteStorePtr bsp, Nlm_VoidPtr ptr, Nlm_Int4 len)
728 
729 {
730 	Nlm_Int4 added;
731 
732 	added = Nlm_BSAdd(bsp, len, FALSE);
733 	if (added != len)
734 	{
735 		Nlm_BSDelete(bsp, added);
736 		return 0;
737 	}
738 	added = Nlm_BSWrite(bsp, ptr, len);
739 	return added;
740 }
741 
742 /*****************************************************************************
743 *
744 *   Int4 BSInsertFromBS(bsp, bsp2, len)
745 *   	returns bytes written from bsp2 into bsp
746 *       reads from bsp2 starting from current seek position
747 *       writes from current seekptr position
748 *       seekptr left pointing after last byte written
749 *       allocates storage if needed
750 *       inserts data BEFORE seekptr
751 *
752 *****************************************************************************/
Nlm_BSInsertFromBS(Nlm_ByteStorePtr bsp,Nlm_ByteStorePtr bsp2,Nlm_Int4 len)753 NLM_EXTERN Nlm_Int4 LIBCALL  Nlm_BSInsertFromBS (Nlm_ByteStorePtr bsp, Nlm_ByteStorePtr bsp2, Nlm_Int4 len)
754 {
755 	Nlm_Int4 added;
756 	Nlm_Int2 x;
757 
758 	added = Nlm_BSAdd(bsp, len, FALSE);
759 	if (added != len)
760 	{
761 		Nlm_BSDelete(bsp, added);
762 		return 0;
763 	}
764 
765 	for (added = 0; added < len; added++)
766 	{
767 		x = Nlm_BSGetByte(bsp2);
768 		Nlm_BSPutByte(bsp, x);
769 	}
770 	return added;
771 }
772 
773 /*****************************************************************************
774 *
775 *   ByteStorePtr Nlm_BSFree(bsp)
776 *
777 *****************************************************************************/
Nlm_BSFree(Nlm_ByteStorePtr bsp)778 NLM_EXTERN Nlm_ByteStorePtr LIBCALL  Nlm_BSFree (Nlm_ByteStorePtr bsp)
779 
780 {
781 	Nlm_BSUnitPtr bsup, tmp;
782 
783 	if (bsp == NULL)
784 		return NULL;
785 
786 	bsup = bsp->chain;
787 	while (bsup != NULL)
788 	{
789 		tmp = bsup;
790 		bsup = bsup->next;
791 		Nlm_HandFree(tmp->str);
792 		Nlm_MemFree(tmp);
793 	}
794 	return (Nlm_ByteStorePtr) Nlm_MemFree(bsp);
795 }
796 
797 /*****************************************************************************
798 *
799 *   ByteStorePtr Nlm_BSDup(bsp)
800 *
801 *****************************************************************************/
802 
803 #define BUFSIZE 256
804 
Nlm_BSDup(Nlm_ByteStorePtr source)805 NLM_EXTERN Nlm_ByteStorePtr LIBCALL Nlm_BSDup (Nlm_ByteStorePtr source)
806 
807 {
808   Nlm_Byte          buf [BUFSIZE + 4];
809   Nlm_Int4          count;
810   Nlm_ByteStorePtr  dest;
811   Nlm_Int4          sourceLen;
812   Nlm_Int4          sourceLoc;
813 
814   dest = NULL;
815   if (source != NULL) {
816     sourceLen = Nlm_BSLen (source);
817     dest = Nlm_BSNew (sourceLen);
818     /* read the original location */
819     sourceLoc = Nlm_BSTell(source);
820     Nlm_BSSeek(source, 0L, SEEK_SET);
821     if (dest != NULL) {
822       count = MIN (sourceLen, (Nlm_Int4) BUFSIZE);
823       while (count > 0 && sourceLen > 0) {
824         Nlm_BSRead (source, buf, count);
825         Nlm_BSWrite (dest, buf, count);
826         sourceLen -= count;
827         count = MIN (sourceLen, (Nlm_Int4) BUFSIZE);
828       }
829       /* for neatness, make the duplicate point to the
830 	     same location as the old one */
831       Nlm_BSSeek(dest, sourceLoc, SEEK_SET);
832     }
833     /* restore original location */
834     Nlm_BSSeek(source, sourceLoc, SEEK_SET);
835   }
836   return dest;
837 }
838 
839 /*****************************************************************************
840 *
841 *   Boolean Nlm_BSEqual (bs1, bs2)
842 *
843 *****************************************************************************/
844 
Nlm_BSEqual(Nlm_ByteStorePtr bs1,Nlm_ByteStorePtr bs2)845 NLM_EXTERN Nlm_Boolean LIBCALL Nlm_BSEqual (Nlm_ByteStorePtr bs1, Nlm_ByteStorePtr bs2)
846 
847 {
848   Nlm_Byte  buf1 [256], buf2 [256];
849   Nlm_Int4  count1, count2, idx;
850 
851   if (bs1 == NULL || bs2 == NULL) {
852     if (bs1 == NULL && bs2 == NULL) return TRUE;
853     if (Nlm_BSLen (bs1) == 0 && Nlm_BSLen (bs2) == 0) return TRUE;
854     return FALSE;
855   }
856 
857   Nlm_BSSeek (bs1, 0, SEEK_SET);
858   Nlm_BSSeek (bs2, 0, SEEK_SET);
859 
860   count1 = Nlm_BSRead (bs1, buf1, sizeof (buf1));
861   count2 = Nlm_BSRead (bs2, buf2, sizeof (buf2));
862 
863   while (count1 == count2 && count2 > 0) {
864     for (idx = 0; idx < count1; idx++) {
865       if (buf1 [idx] != buf2 [idx]) return FALSE;
866     }
867 
868     count1 = Nlm_BSRead (bs1, buf1, sizeof (buf1));
869     count2 = Nlm_BSRead (bs2, buf2, sizeof (buf2));
870   }
871 
872   if (count1 != count2) return FALSE;
873 
874   return TRUE;
875 }
876 
877 
878 /* for copying and swapping of UID lists passed over network to BIG_ENDIAN server */
879 
Nlm_BSDupAndSwapUint4(Nlm_ByteStorePtr source)880 NLM_EXTERN Nlm_ByteStorePtr LIBCALL Nlm_BSDupAndSwapUint4 (Nlm_ByteStorePtr source)
881 
882 {
883   Nlm_Byte          buf [BUFSIZE + 4];
884   Nlm_Int4          count;
885   Nlm_ByteStorePtr  dest;
886   Nlm_Int4          sourceLen;
887   Nlm_Int4          sourceLoc;
888   Nlm_Int4          swapLen;
889 
890   dest = NULL;
891   if (source != NULL) {
892     sourceLen = Nlm_BSLen (source);
893     dest = Nlm_BSNew (sourceLen);
894     /* read the original location */
895     sourceLoc = Nlm_BSTell(source);
896     Nlm_BSSeek(source, 0L, SEEK_SET);
897     if (dest != NULL) {
898       count = MIN (sourceLen, (Nlm_Int4) BUFSIZE);
899       while (count > 0 && sourceLen > 0) {
900         swapLen = Nlm_BSRead (source, buf, count);
901         swapLen /= 4;
902         /* swap Uint4 if IS_LITTLE_ENDIAN */
903         Nlm_SwapUint4Buff ((Nlm_Uint4Ptr) buf, swapLen);
904         Nlm_BSWrite (dest, buf, count);
905         sourceLen -= count;
906         count = MIN (sourceLen, (Nlm_Int4) BUFSIZE);
907       }
908       /* for neatness, make the duplicate point to the
909 	     same location as the old one */
910       Nlm_BSSeek(dest, sourceLoc, SEEK_SET);
911     }
912     /* restore original location */
913     Nlm_BSSeek(source, sourceLoc, SEEK_SET);
914   }
915   return dest;
916 }
917 
918 /****************************************************************************
919 *
920 *   Integer storage utilities
921 *      These assume integers are store in BIG_ENDIAN order in the ByteStore
922 *      They read and write Uint2 or Uint4 in the NATIVE endian order
923 *      All work with UNSIGNED 2 or 4 byte integers
924 *         (you should cast to make them signed)
925 *      These are just helper functions. They do no internal consistency
926 *         checking.
927 *      They are primarily to facilitate encoding SEQUENCE OF INTEGER as
928 *         OCTET STRING for ASN.1
929 *
930 ****************************************************************************/
931 
Nlm_BSGetUint2(Nlm_ByteStorePtr bsp)932 NLM_EXTERN Nlm_Uint2 LIBCALL Nlm_BSGetUint2 (Nlm_ByteStorePtr bsp)
933 {
934 	Nlm_Uint2 retval = 0;
935 
936 	Nlm_BSRead(bsp, (Nlm_VoidPtr)(&retval), (Nlm_Int4)2);
937 	Nlm_SwapUint2(retval);
938 
939 	return retval;
940 }
941 
Nlm_BSGetUint4(Nlm_ByteStorePtr bsp)942 NLM_EXTERN Nlm_Uint4 LIBCALL Nlm_BSGetUint4 (Nlm_ByteStorePtr bsp)
943 {
944 	Nlm_Uint4 retval = 0;
945 
946 	Nlm_BSRead(bsp, (Nlm_VoidPtr)(&retval), (Nlm_Int4)4);
947 	Nlm_SwapUint4(retval);
948 
949 	return retval;
950 }
951 
Nlm_BSPutUint2(Nlm_ByteStorePtr bsp,Nlm_Uint2 value)952 NLM_EXTERN Nlm_Int2 LIBCALL Nlm_BSPutUint2 (Nlm_ByteStorePtr bsp, Nlm_Uint2 value)
953 {
954 #ifdef IS_LITTLE_ENDIAN
955 	Nlm_SwitchUint2(value);
956 #endif
957 	if (Nlm_BSWrite(bsp, (Nlm_VoidPtr)(&value), (Nlm_Int4)2) == (Nlm_Int2)2)
958 		return (Nlm_Int2)1;
959 	else
960 		return (Nlm_Int2)0;
961 }
962 
Nlm_BSPutUint4(Nlm_ByteStorePtr bsp,Nlm_Uint4 value)963 NLM_EXTERN Nlm_Int2 LIBCALL Nlm_BSPutUint4 (Nlm_ByteStorePtr bsp, Nlm_Uint4 value)
964 {
965 #ifdef IS_LITTLE_ENDIAN
966 	Nlm_SwitchUint4(value);
967 #endif
968 	if (Nlm_BSWrite(bsp, (Nlm_VoidPtr)(&value), (Nlm_Int4)4) == (Nlm_Int2)4)
969 		return (Nlm_Int2)1;
970 	else
971 		return (Nlm_Int2)0;
972 }
973 
974        /* In functions below, size is 2 or 4 */
975        /* Integers are converted from ByteStore to native endian (BSUintXRead) */
976 	   /*   or from native endian to ByteStore (BSUintXWrite) */
977 	   /* len is number of INTEGERS, not number of bytes */
978 	   /* returns count of integers put in ptr */
979 	   /* WARNING: On LITTLE_ENDIAN machines the data in ptr is changed to BIG_ENDIAN in the */
980 	   /*   XXWrite functions and LEFT THAT WAY */
Nlm_BSUint4Read(Nlm_ByteStorePtr bsp,Nlm_Uint4Ptr ptr,Nlm_Int4 len)981 NLM_EXTERN Nlm_Int4 LIBCALL Nlm_BSUint4Read (Nlm_ByteStorePtr bsp, Nlm_Uint4Ptr ptr, Nlm_Int4 len)
982 {
983 	Nlm_Int4 len2;
984 
985 	len2 = Nlm_BSRead(bsp, (Nlm_VoidPtr)ptr, (len * 4));
986 	len2 /= 4;
987 	Nlm_SwapUint4Buff(ptr, len2);
988 	return len2;
989 }
990 
Nlm_BSUint4Write(Nlm_ByteStorePtr bsp,Nlm_Uint4Ptr ptr,Nlm_Int4 len)991 NLM_EXTERN Nlm_Int4 LIBCALL Nlm_BSUint4Write (Nlm_ByteStorePtr bsp, Nlm_Uint4Ptr ptr, Nlm_Int4 len)
992 {
993 	Nlm_Int4 len2;
994 
995 #ifdef IS_LITTLE_ENDIAN
996 	Nlm_SwitchUint4Buff(ptr, len);
997 #endif
998 	len2 = Nlm_BSWrite(bsp, (Nlm_VoidPtr)ptr, (len * 4));
999 	return (len2 / 4);
1000 }
1001 
Nlm_BSUint2Read(Nlm_ByteStorePtr bsp,Nlm_Uint2Ptr ptr,Nlm_Int4 len)1002 NLM_EXTERN Nlm_Int4 LIBCALL Nlm_BSUint2Read (Nlm_ByteStorePtr bsp, Nlm_Uint2Ptr ptr, Nlm_Int4 len)
1003 {
1004 	Nlm_Int4 len2;
1005 
1006 	len2 = Nlm_BSRead(bsp, (Nlm_VoidPtr)ptr, (len * 2));
1007 	len2 /= 2;
1008 	Nlm_SwapUint2Buff(ptr, len2);
1009 	return len2;
1010 }
1011 
Nlm_BSUint2Write(Nlm_ByteStorePtr bsp,Nlm_Uint2Ptr ptr,Nlm_Int4 len)1012 NLM_EXTERN Nlm_Int4 LIBCALL Nlm_BSUint2Write (Nlm_ByteStorePtr bsp, Nlm_Uint2Ptr ptr, Nlm_Int4 len)
1013 {
1014 	Nlm_Int4 len2;
1015 
1016 #ifdef IS_LITTLE_ENDIAN
1017 	Nlm_SwitchUint2Buff(ptr, len);
1018 #endif
1019 	len2 = Nlm_BSWrite(bsp, (Nlm_VoidPtr)ptr, (len * 2));
1020 	return (len2 / 2);
1021 }
1022 
1023