1 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
2 * Copyright by The HDF Group. *
3 * Copyright by the Board of Trustees of the University of Illinois. *
4 * All rights reserved. *
5 * *
6 * This file is part of HDF. The full HDF copyright notice, including *
7 * terms governing use, modification, and redistribution, is contained in *
8 * the COPYING file, which can be found at the root of the source code *
9 * distribution tree, or in https://support.hdfgroup.org/ftp/HDF/releases/. *
10 * If you do not have access to either file, you may request a copy from *
11 * help@hdfgroup.org. *
12 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
13
14 /* $Id$ */
15
16 /*
17 FILE
18 hbitio.c
19 HDF bit level I/O routines
20 REMARKS
21 These functions operate on top of the "H" layer routines
22 (i.e. they call Hstartread, Hstartwrite, Hread, Hseek, Hwrite, etc.)
23 and depend on them for all actual I/O to data elements in the
24 file. This may be somewhat slow, but it prevents having
25 to duplicate code for that access.
26 EXPORTED ROUTINES
27 Hstartbitread - open a dataset for bitfile dataset reading
28 Hstartbitwrite - open a dataset for bitfile dataset writing
29 Happendable - make a writable dataset appendable
30 Hbitread - read bits from a bitfile dataset
31 Hbitwrite - write bits to a bitfile dataset
32 Hbitseek - seek to a given bit offset in a bitfile dataset
33 Hendbitaccess - close off access to a bitfile dataset
34 LOCAL ROUTINES
35 HIbitflush - flush the bits out to a writable bitfile
36 HIget_bitfile_rec - get a free bitfile record
37 HIread2write - switch from reading bits to writing them
38 HIwrite2read - switch from writing bits to reading them
39 AUTHOR
40 Quincey Koziol
41 MODIFICATION HISTORY
42 3/15/92 Starting writing
43 */
44
45 #define BITMASTER
46 #include "hdf.h"
47 #include "hfile.h"
48
49 /* Local Variables */
50
51 /* Whether we've installed the library termination function yet for this interface */
52 PRIVATE intn library_terminate = FALSE;
53
54 /* Local Function Declarations */
55 PRIVATE bitrec_t * HIget_bitfile_rec(void);
56
57 PRIVATE intn HIbitflush(bitrec_t * bitfile_rec, intn flushbit, intn writeout);
58
59 PRIVATE intn HIwrite2read(bitrec_t * bitfile_rec);
60 PRIVATE intn HIread2write(bitrec_t * bitfile_rec);
61
62 PRIVATE intn HIbitstart(void);
63
64 /* #define TESTING */
65 /* Actual Function Definitions */
66
67 /*--------------------------------------------------------------------------
68
69 NAME
70 Hstartbitread -- locate and position a bit-read access elt on a tag/ref
71 USAGE
72 int32 Hstartbitread(fileid, tag, ref)
73 int fileid; IN: id of file to attach access element to
74 int tag; IN: tag to search for
75 int ref; IN: ref to search for
76 RETURNS
77 returns id of bit-access element if successful, otherwise FAIL (-1)
78 DESCRIPTION
79 Calls Hstartread and initializes bit-level structures.
80 GLOBAL VARIABLES
81 COMMENTS, BUGS, ASSUMPTIONS
82 EXAMPLES
83 REVISION LOG
84 --------------------------------------------------------------------------*/
85 int32
Hstartbitread(int32 file_id,uint16 tag,uint16 ref)86 Hstartbitread(int32 file_id, uint16 tag, uint16 ref)
87 {
88 CONSTR(FUNC, "Hstartbitread"); /* for HERROR */
89 int32 aid; /* Access ID for the bit-level routines to use */
90 struct bitrec_t *bitfile_rec; /* Pointer to the bitfile record */
91 int32 ret_value; /* return bit ID */
92
93 /* clear error stack */
94 HEclear();
95
96 /* Perform global, one-time initialization */
97 if (library_terminate == FALSE)
98 if(HIbitstart()==FAIL)
99 HRETURN_ERROR(DFE_CANTINIT, FAIL);
100
101 /* Try to get an AID */
102 if ((aid = Hstartread(file_id, tag, ref)) == FAIL)
103 HRETURN_ERROR(DFE_BADAID, FAIL);
104
105 /* get a slot in the access record array */
106 if ((bitfile_rec = HIget_bitfile_rec()) == NULL)
107 HRETURN_ERROR(DFE_TOOMANY, FAIL);
108
109 bitfile_rec->acc_id = aid;
110 ret_value= HAregister_atom(BITIDGROUP,bitfile_rec);
111 bitfile_rec->bit_id=ret_value;
112 if (HQuerylength(aid, &bitfile_rec->max_offset) == FAIL)
113 HRETURN_ERROR(DFE_INTERNAL, FAIL);
114 bitfile_rec->byte_offset = 0;
115
116 bitfile_rec->access = 'r';
117 bitfile_rec->mode = 'r';
118 bitfile_rec->bytez = bitfile_rec->bytea + BITBUF_SIZE;
119
120 /* pre-read the first block into the buffer */
121 if (bitfile_rec->max_offset > bitfile_rec->byte_offset)
122 {
123 int32 read_size; /* number of bytes to read into buffer */
124 int32 n; /* number of bytes actually read */
125
126 read_size = MIN((bitfile_rec->max_offset - bitfile_rec->byte_offset), BITBUF_SIZE);
127 if ((n = Hread(bitfile_rec->acc_id, read_size, bitfile_rec->bytea)) == FAIL)
128 return (FAIL); /* EOF? somebody pulled the rug out from under us! */
129 bitfile_rec->buf_read = (intn) n; /* keep track of the number of bytes in buffer */
130 bitfile_rec->bytep = bitfile_rec->bytea; /* set to the beginning of the buffer */
131 } /* end if */
132 else
133 {
134 bitfile_rec->bytep = bitfile_rec->bytez; /* set to the end of the buffer to force read */
135 bitfile_rec->buf_read = 0; /* set the number of bytes in buffer to 0 */
136 } /* end else */
137 bitfile_rec->block_offset = 0;
138 bitfile_rec->count = 0;
139
140 return(ret_value);
141 } /* Hstartbitread() */
142
143 /*--------------------------------------------------------------------------
144
145 NAME
146 Hstartbitwrite -- set up a bit access elt for a write
147 USAGE
148 int32 Hstartbitwrite(fileid, tag, ref, len)
149 int fileid; IN: id of file to write to
150 int tag; IN: tag to write to
151 int ref; IN: ref to write to
152 long length; IN: the length of the data element (in bytes)
153 RETURNS
154 returns id of bit access element if successful and FAIL otherwise
155 DESCRIPTION
156 Set up a bit-write access elt to write out a data element. Calls
157 Hstartwrite for most initialization and just initializes the bit-
158 level stuff here.
159 GLOBAL VARIABLES
160 COMMENTS, BUGS, ASSUMPTIONS
161 EXAMPLES
162 REVISION LOG
163 --------------------------------------------------------------------------*/
164 int32
Hstartbitwrite(int32 file_id,uint16 tag,uint16 ref,int32 length)165 Hstartbitwrite(int32 file_id, uint16 tag, uint16 ref, int32 length)
166 {
167 CONSTR(FUNC, "Hstartbitwrite"); /* for HERROR */
168 bitrec_t *bitfile_rec; /* access record */
169 int32 aid; /* Access ID for the bit-level routines to use */
170 intn exists; /* whether dataset exists already */
171 int32 ret_value; /* return bit ID */
172
173 /* clear error stack and check validity of file id */
174 HEclear();
175
176 /* Perform global, one-time initialization */
177 if (library_terminate == FALSE)
178 if(HIbitstart()==FAIL)
179 HRETURN_ERROR(DFE_CANTINIT, FAIL);
180
181 exists = (Hexist(file_id, tag, ref) == SUCCEED) ? TRUE : FALSE;
182
183 /* Try to get an AID */
184 if ((aid = Hstartwrite(file_id, tag, ref, length)) == FAIL)
185 HRETURN_ERROR(DFE_BADAID, FAIL);
186
187 /* get empty slot in bit-access records */
188 if ((bitfile_rec = HIget_bitfile_rec()) == NULL)
189 HRETURN_ERROR(DFE_TOOMANY, FAIL);
190
191 bitfile_rec->acc_id = aid;
192 ret_value= HAregister_atom(BITIDGROUP,bitfile_rec);
193 bitfile_rec->bit_id=ret_value;
194 bitfile_rec->byte_offset = 0;
195 bitfile_rec->block_offset = 0;
196 if (exists == TRUE)
197 {
198 if (HQuerylength(aid, &bitfile_rec->max_offset) == FAIL)
199 HRETURN_ERROR(DFE_INTERNAL, FAIL);
200
201 /* pre-read the first block into the buffer */
202 if (bitfile_rec->max_offset > bitfile_rec->byte_offset)
203 {
204 int32 read_size; /* number of bytes to read into buffer */
205 int32 n; /* number of bytes actually read */
206
207 read_size = MIN((bitfile_rec->max_offset - bitfile_rec->byte_offset), BITBUF_SIZE);
208 if ((n = Hread(bitfile_rec->acc_id, read_size, bitfile_rec->bytea)) == FAIL)
209 HRETURN_ERROR(DFE_READERROR, FAIL); /* EOF? somebody pulled the rug out from under us! */
210 bitfile_rec->buf_read = (intn) n; /* keep track of the number of bytes in buffer */
211 if (Hseek(bitfile_rec->acc_id, bitfile_rec->block_offset, DF_START) == FAIL)
212 HRETURN_ERROR(DFE_SEEKERROR, FAIL);
213 } /* end if */
214 } /* end if */
215 else
216 {
217 bitfile_rec->max_offset = 0;
218 bitfile_rec->buf_read = 0; /* set the number of bytes in buffer to 0 */
219 } /* end else */
220 bitfile_rec->access = 'w';
221 bitfile_rec->mode = 'w';
222 bitfile_rec->bytez = bitfile_rec->bytea + BITBUF_SIZE;
223 bitfile_rec->bytep = bitfile_rec->bytea; /* set to the beginning of the buffer */
224 bitfile_rec->count = BITNUM;
225 bitfile_rec->bits = 0;
226
227 return ret_value;
228 } /* end Hstartbitwrite() */
229
230 /*--------------------------------------------------------------------------
231
232 NAME
233 Hbitappendable -- make a bitio AID appendable
234 USAGE
235 intn Hbitappendable(bitid)
236 int32 bitid; IN: id of bit-element to make appendable
237 RETURNS
238 SUCCEED for success
239 FAIL to indicate failure
240 DESCRIPTION
241 If a dataset is at the end of a file, allow Hbitwrite()s to write
242 past the end of a file. Allows expanding datasets without the use
243 of linked blocks.
244 GLOBAL VARIABLES
245 COMMENTS, BUGS, ASSUMPTIONS
246 EXAMPLES
247 REVISION LOG
248 --------------------------------------------------------------------------*/
249 intn
Hbitappendable(int32 bitid)250 Hbitappendable(int32 bitid)
251 {
252 CONSTR(FUNC, "Hbitappendable"); /* for HERROR */
253 bitrec_t *bitfile_rec; /* access record */
254
255 /* clear error stack and check validity of file id */
256 HEclear();
257
258 if ((bitfile_rec = HAatom_object(bitid)) == NULL)
259 HRETURN_ERROR(DFE_ARGS, FAIL);
260
261 /* Check for write access */
262 if (bitfile_rec->access != 'w')
263 HRETURN_ERROR(DFE_BADACC, FAIL);
264
265 if (Happendable(bitfile_rec->acc_id) == FAIL)
266 HRETURN_ERROR(DFE_NOTENOUGH, FAIL);
267 return (SUCCEED);
268 } /* end Hbitappendable() */
269
270 /*--------------------------------------------------------------------------
271
272 NAME
273 Hbitwrite -- write a number of bits out to a bit-element
274 USAGE
275 intn Hbitwrite(bitid, count, data)
276 int32 bitid; IN: id of bit-element to write to
277 intn count; IN: number of bits to write
278 uint32 data; IN: actual data bits to output
279 (bits to output must be in the low bits)
280 RETURNS
281 the number of bits written for successful write,
282 FAIL to indicate failure
283 DESCRIPTION
284 Write a number of bits out to a bit-element. This function
285 buffers the bits and then writes them out when appropriate
286 with Hwrite().
287 GLOBAL VARIABLES
288 COMMENTS, BUGS, ASSUMPTIONS
289 EXAMPLES
290 REVISION LOG
291 --------------------------------------------------------------------------*/
292 intn
Hbitwrite(int32 bitid,intn count,uint32 data)293 Hbitwrite(int32 bitid, intn count, uint32 data)
294 {
295 CONSTR(FUNC, "Hbitwrite"); /* for HERROR */
296 static int32 last_bit_id=(-1); /* the bit ID of the last bitfile_record accessed */
297 static bitrec_t *bitfile_rec=NULL; /* access record */
298 intn orig_count = count; /* keep track of orig, number of bits to output */
299
300 /* clear error stack and check validity of file id */
301 HEclear();
302
303 if (count <= 0)
304 HRETURN_ERROR(DFE_ARGS, FAIL);
305
306 /* cache the bitfile_record since this routine gets called so many times */
307 if(bitid!=last_bit_id)
308 {
309 /* This needs a mutex semaphore when we go to a multi-threaded version of the library -QAK */
310 bitfile_rec = HAatom_object(bitid);
311 last_bit_id=bitid;
312 } /* end if */
313
314 if (bitfile_rec == NULL)
315 HRETURN_ERROR(DFE_ARGS, FAIL);
316
317 /* Check for write access */
318 if (bitfile_rec->access != 'w')
319 HRETURN_ERROR(DFE_BADACC, FAIL);
320
321 if (count > (intn)DATANUM)
322 count = (intn)DATANUM;
323
324 /* change bitfile modes if necessary */
325 if (bitfile_rec->mode == 'r')
326 HIread2write(bitfile_rec);
327
328 data &= maskl[count];
329
330 /* if the new bits will not fill up a byte, then just */
331 /* merge the new bits into the current bits buffer */
332 if (count < bitfile_rec->count)
333 {
334 bitfile_rec->bits |= (uint8)(data << (bitfile_rec->count -= count));
335 return (orig_count);
336 } /* end if */
337
338 /* fill up the current bits buffer and output the byte */
339 *(bitfile_rec->bytep) = (uint8) (bitfile_rec->bits | (uint8)(data >> (count -= bitfile_rec->count)));
340 bitfile_rec->byte_offset++;
341 if (++bitfile_rec->bytep == bitfile_rec->bytez)
342 {
343 int32 write_size;
344
345 write_size = bitfile_rec->bytez - bitfile_rec->bytea;
346 bitfile_rec->bytep = bitfile_rec->bytea;
347 if (Hwrite(bitfile_rec->acc_id, write_size, bitfile_rec->bytea) == FAIL)
348 HRETURN_ERROR(DFE_WRITEERROR, FAIL);
349 bitfile_rec->block_offset += write_size;
350
351 /* check if we should pre-read the next block into the buffer */
352 if (bitfile_rec->max_offset > bitfile_rec->byte_offset)
353 {
354 int32 read_size; /* number of bytes to read into buffer */
355 int32 n; /* number of bytes actually read */
356
357 read_size = MIN((bitfile_rec->max_offset - bitfile_rec->byte_offset), BITBUF_SIZE);
358 if ((n = Hread(bitfile_rec->acc_id, read_size, bitfile_rec->bytea)) == FAIL)
359 HRETURN_ERROR(DFE_READERROR, FAIL); /* EOF? somebody pulled the rug out from under us! */
360 bitfile_rec->buf_read = n; /* keep track of the number of bytes in buffer */
361 if (Hseek(bitfile_rec->acc_id, bitfile_rec->block_offset, DF_START) == FAIL)
362 HRETURN_ERROR(DFE_SEEKERROR, FAIL);
363 } /* end if */
364 } /* end if */
365
366 /* output any and all remaining whole bytes */
367 while (count >= (intn)BITNUM)
368 {
369 *(bitfile_rec->bytep) = (uint8) (data >> (count -= (intn)BITNUM));
370 bitfile_rec->byte_offset++;
371 if (++bitfile_rec->bytep == bitfile_rec->bytez)
372 {
373 int32 write_size;
374
375 write_size = bitfile_rec->bytez - bitfile_rec->bytea;
376 bitfile_rec->bytep = bitfile_rec->bytea;
377 if (Hwrite(bitfile_rec->acc_id, write_size, bitfile_rec->bytea) == FAIL)
378 HRETURN_ERROR(DFE_WRITEERROR, FAIL);
379 bitfile_rec->block_offset += write_size;
380
381 /* check if we should pre-read the next block into the buffer */
382 if (bitfile_rec->max_offset > bitfile_rec->byte_offset)
383 {
384 int32 read_size; /* number of bytes to read into buffer */
385 int32 n; /* number of bytes actually read */
386
387 read_size = MIN((bitfile_rec->max_offset - bitfile_rec->byte_offset), BITBUF_SIZE);
388 if ((n = Hread(bitfile_rec->acc_id, read_size, bitfile_rec->bytea)) == FAIL)
389 HRETURN_ERROR(DFE_READERROR, FAIL); /* EOF? somebody pulled the rug out from under us! */
390 bitfile_rec->buf_read = n; /* keep track of the number of bytes in buffer */
391 if (Hseek(bitfile_rec->acc_id, bitfile_rec->block_offset, DF_START) == FAIL)
392 HRETURN_ERROR(DFE_SEEKERROR, FAIL);
393 } /* end if */
394 } /* end if */
395 } /* end while */
396
397 /* put any remaining bits into the bits buffer */
398 if ((bitfile_rec->count = (intn)BITNUM - count) > 0)
399 bitfile_rec->bits = (uint8) (data << bitfile_rec->count);
400
401 /* Update the offset in the buffer */
402 if (bitfile_rec->byte_offset > bitfile_rec->max_offset)
403 bitfile_rec->max_offset = bitfile_rec->byte_offset;
404
405 return (orig_count);
406 } /* end Hbitwrite() */
407
408 /*--------------------------------------------------------------------------
409
410 NAME
411 Hbitread -- read a number of bits from a bit-element
412 USAGE
413 intn Hbitread(bitid, count, data)
414 int32 bitid; IN: id of bit-element to write to
415 intn count; IN: number of bits to write
416 uint32 *data; IN: pointer to the bits to read
417 OUT: points to the bits read in
418 (bits input will be in the low bits)
419 RETURNS
420 the number of bits read for successful write,
421 FAIL to indicate failure
422 DESCRIPTION
423 Read a number of bits from a bit-element. This function
424 buffers the bits and then reads them when appropriate
425 with Hread().
426 GLOBAL VARIABLES
427 COMMENTS, BUGS, ASSUMPTIONS
428 EXAMPLES
429 REVISION LOG
430 --------------------------------------------------------------------------*/
431 intn
Hbitread(int32 bitid,intn count,uint32 * data)432 Hbitread(int32 bitid, intn count, uint32 *data)
433 {
434 CONSTR(FUNC, "Hbitread"); /* for HERROR */
435 static int32 last_bit_id=(-1); /* the bit ID of the last bitfile_record accessed */
436 static bitrec_t *bitfile_rec=NULL; /* access record */
437 uint32 l;
438 uint32 b = 0; /* bits to return */
439 intn orig_count; /* the original number of bits to read in */
440 int32 n;
441
442 /* clear error stack and check validity of file id */
443 HEclear();
444
445 if (count <= 0)
446 HRETURN_ERROR(DFE_ARGS, FAIL);
447
448 /* cache the bitfile_record since this routine gets called so many times */
449 if(bitid!=last_bit_id)
450 {
451 /* This needs a mutex semaphore when we go to a multi-threaded version of the library -QAK */
452 bitfile_rec = HAatom_object(bitid);
453 last_bit_id=bitid;
454 } /* end if */
455
456 if (bitfile_rec == NULL)
457 HRETURN_ERROR(DFE_ARGS, FAIL);
458
459 /* Check for write access */
460 /* change bitfile modes if necessary */
461 if (bitfile_rec->mode == 'w')
462 HIwrite2read(bitfile_rec);
463
464 if (count > (intn)DATANUM) /* truncate the count if it's too large */
465 count = DATANUM;
466
467 /* if the request can be satisfied with just the */
468 /* buffered bits then do the shift and return */
469 if (count <= bitfile_rec->count)
470 {
471 *data = (uint32)((uintn)bitfile_rec->bits >> (bitfile_rec->count -= count)) & (uint32) maskc[count];
472 return (count);
473 } /* end if */
474
475 /* keep track of the original number of bits to read in */
476 orig_count = count;
477
478 /* get all the buffered bits into the correct position first */
479 if (bitfile_rec->count > 0)
480 {
481 b = (uint32)(bitfile_rec->bits & maskc[bitfile_rec->count]);
482 b <<= (count -= bitfile_rec->count);
483 } /* end if */
484
485 /* bring in as many whole bytes as the request allows */
486 while (count >= (intn)BITNUM)
487 {
488 if (bitfile_rec->bytep == bitfile_rec->bytez)
489 {
490 n = Hread(bitfile_rec->acc_id, BITBUF_SIZE, bitfile_rec->bytea);
491 if (n == FAIL)
492 { /* EOF */
493 bitfile_rec->count = 0; /* make certain that we don't try to access the file->bits information */
494 *data = b; /* assign the bits read in */
495 return (orig_count - count); /* break out now */
496 } /* end if */
497 bitfile_rec->block_offset += bitfile_rec->buf_read; /* keep track of the number of bytes in buffer */
498 bitfile_rec->bytez = n + (bitfile_rec->bytep = bitfile_rec->bytea);
499 bitfile_rec->buf_read = n; /* keep track of the number of bytes in buffer */
500 } /* end if */
501 l = (uint32) (*bitfile_rec->bytep++);
502 b |= (uint32)(l << (count -= (intn)BITNUM));
503 bitfile_rec->byte_offset++;
504 if (bitfile_rec->byte_offset > bitfile_rec->max_offset)
505 bitfile_rec->max_offset = bitfile_rec->byte_offset;
506 } /* end while */
507
508 /* split any partial request with the bits buffer */
509 if (count > 0)
510 {
511 if (bitfile_rec->bytep == bitfile_rec->bytez)
512 {
513 n = Hread(bitfile_rec->acc_id, BITBUF_SIZE, bitfile_rec->bytea);
514 if (n == FAIL)
515 { /* EOF */
516 bitfile_rec->count = 0; /* make certain that we don't try to access the file->bits information */
517 *data = b; /* assign the bits read in */
518 return (orig_count - count); /* return now */
519 } /* end if */
520 bitfile_rec->block_offset += bitfile_rec->buf_read; /* keep track of the number of bytes in buffer */
521 bitfile_rec->bytez = n + (bitfile_rec->bytep = bitfile_rec->bytea);
522 bitfile_rec->buf_read = n; /* keep track of the number of bytes in buffer */
523 } /* end if */
524 bitfile_rec->count = ((intn)BITNUM - count);
525 l = (uint32) (bitfile_rec->bits = *bitfile_rec->bytep++);
526 b |= l >> bitfile_rec->count;
527 bitfile_rec->byte_offset++;
528 if (bitfile_rec->byte_offset > bitfile_rec->max_offset)
529 bitfile_rec->max_offset = bitfile_rec->byte_offset;
530 } /* end if */
531 else
532 bitfile_rec->count = 0;
533
534 *data = b;
535 return (orig_count);
536 } /* end Hbitread() */
537
538 /*--------------------------------------------------------------------------
539
540 NAME
541 Hbitseek -- seek to a given bit position in a bit-element
542 USAGE
543 intn Hbitseek(bitid, offset)
544 int32 bitid; IN: id of bit-element to write to
545 intn byte_offset; IN: byte offset in the bit-element
546 intn bit_offset; IN: bit offset from the byte offset
547
548 RETURNS
549 returns FAIL (-1) if fail, SUCCEED (0) otherwise.
550 DESCRIPTION
551 Seek to a bit offset in a bit-element.
552 GLOBAL VARIABLES
553 COMMENTS, BUGS, ASSUMPTIONS
554 EXAMPLES
555 If seeking to the 15th bit in a bit-element, the call would look like:
556 Hbitseek(bitid,1,7);
557
558 Converting from a direct bit offset variable to this call looks like:
559 Hbitseek(bitid,bit_offset/8,bit_offset%8);
560 REVISION LOG
561 --------------------------------------------------------------------------*/
562 intn
Hbitseek(int32 bitid,int32 byte_offset,intn bit_offset)563 Hbitseek(int32 bitid, int32 byte_offset, intn bit_offset)
564 {
565 CONSTR(FUNC, "Hbitseek"); /* for HERROR */
566 bitrec_t *bitfile_rec; /* access record */
567 int32 seek_pos; /* position of block to seek to */
568 int32 read_size; /* number of bytes to read into buffer */
569 int32 n; /* number of bytes actually read */
570 intn new_block; /* whether to move to another block in the dataset */
571
572 /* clear error stack and check validity of file id */
573 HEclear();
574
575 if (byte_offset < 0 || bit_offset < 0 || bit_offset > ((intn)BITNUM - 1)
576 || (bitfile_rec = HAatom_object(bitid)) == NULL
577 || byte_offset > bitfile_rec->max_offset)
578 HRETURN_ERROR(DFE_ARGS, FAIL);
579
580 /* determine whether we need to seek to another block in the file */
581 new_block = (byte_offset < bitfile_rec->block_offset
582 || byte_offset >= bitfile_rec->block_offset + BITBUF_SIZE)
583 ? TRUE : FALSE;
584 if (bitfile_rec->mode == 'w')
585 if (HIbitflush(bitfile_rec, -1, new_block) == FAIL) /* flush, but merge */
586 HRETURN_ERROR(DFE_WRITEERROR, FAIL);
587
588 if (new_block == TRUE)
589 {
590 seek_pos = (byte_offset / BITBUF_SIZE) * BITBUF_SIZE;
591 if (Hseek(bitfile_rec->acc_id, seek_pos, DF_START) == FAIL)
592 HRETURN_ERROR(DFE_SEEKERROR, FAIL);
593
594 read_size = MIN((bitfile_rec->max_offset - seek_pos), BITBUF_SIZE);
595 if ((n = Hread(bitfile_rec->acc_id, read_size, bitfile_rec->bytea)) == FAIL)
596 HRETURN_ERROR(DFE_READERROR, FAIL); /* EOF? somebody pulled the rug out from under us! */
597 bitfile_rec->bytez = n + (bitfile_rec->bytep = bitfile_rec->bytea);
598 bitfile_rec->buf_read = n; /* keep track of the number of bytes in buffer */
599 bitfile_rec->block_offset = seek_pos;
600 if (bitfile_rec->mode == 'w') /* if writing, return the file offset to it's original position */
601 if (Hseek(bitfile_rec->acc_id, seek_pos, DF_START) == FAIL)
602 HRETURN_ERROR(DFE_SEEKERROR, FAIL);
603 } /* end if */
604
605 bitfile_rec->byte_offset = byte_offset;
606
607 /* set to the correct position in the buffer */
608 bitfile_rec->bytep = bitfile_rec->bytea + (byte_offset - bitfile_rec->block_offset);
609 if (bit_offset > 0)
610 {
611 bitfile_rec->count = ((intn)BITNUM - bit_offset);
612 if (bitfile_rec->mode == 'w')
613 { /* if writing, mask off bits not yet written */
614 bitfile_rec->bits = *(bitfile_rec->bytep);
615 bitfile_rec->bits &= maskc[bit_offset] << bitfile_rec->count;
616 } /* end if */
617 else
618 {
619 bitfile_rec->bits = *bitfile_rec->bytep++;
620 } /* end else */
621 } /* end if */
622 else
623 {
624 if (bitfile_rec->mode == 'w')
625 { /* if writing, mask off bits not yet written */
626 bitfile_rec->count = BITNUM;
627 bitfile_rec->bits = 0;
628 } /* end if */
629 else
630 {
631 bitfile_rec->count = 0;
632 } /* end else */
633 } /* end else */
634
635 return (SUCCEED);
636 } /* end Hbitseek() */
637
638 /*--------------------------------------------------------------------------
639
640 NAME
641 Hgetbit -- read 1 bit from a bit-element
642 USAGE
643 intn Hgetbit(bitid)
644 int32 bitid; IN: id of bit-element to read from
645 RETURNS
646 the bit read in (0/1) on success, FAIL(-1) to indicate failure
647 DESCRIPTION
648 Read one bit from a bit-element. This function is mostly a wrapper
649 around Hbitread.
650 GLOBAL VARIABLES
651 COMMENTS, BUGS, ASSUMPTIONS
652 EXAMPLES
653 REVISION LOG
654 --------------------------------------------------------------------------*/
655 intn
Hgetbit(int32 bitid)656 Hgetbit(int32 bitid)
657 {
658 CONSTR(FUNC, "Hgetbit"); /* for HERROR */
659 uint32 data;
660
661 if (Hbitread(bitid, 1, &data) == FAIL)
662 HRETURN_ERROR(DFE_BITREAD, FAIL)
663 return ((intn) data);
664 } /* end Hgetbit() */
665
666 #ifdef OLD_WAY
667 /*--------------------------------------------------------------------------
668
669 NAME
670 Hputbit -- write 1 bit to a bit-element
671 USAGE
672 intn Hputbit(bitid,bit)
673 int32 bitid; IN: id of bit-element to read from
674 intn bit; IN: bit to write
675 RETURNS
676 SUCCEED on success, FAIL(-1) to indicate failure
677 DESCRIPTION
678 Write one bit to a bit-element. This function is mostly a wrapper
679 around Hbitwrite.
680 GLOBAL VARIABLES
681 COMMENTS, BUGS, ASSUMPTIONS
682 EXAMPLES
683 REVISION LOG
684 --------------------------------------------------------------------------*/
685 intn
Hputbit(int32 bitid,intn bit)686 Hputbit(int32 bitid, intn bit)
687 {
688 CONSTR(FUNC, "Hputbit"); /* for HERROR */
689
690 if (Hbitwrite(bitid, 1, (uint32) bit) == FAIL)
691 HRETURN_ERROR(DFE_BITWRITE, FAIL)
692 return (SUCCEED);
693 } /* end Hputbit() */
694 #endif /* OLD_WAY */
695
696 /*--------------------------------------------------------------------------
697
698 NAME
699 Hendbitaccess -- to dispose of a bitfile element
700 USAGE
701 int32 Hendbitaccess(bitfile_id,flushbit)
702 int32 bitfile_id; IN: id of bitfile element to dispose of
703 intn flushbit; IN: determines how to flush leftover bits
704 (leftover bits are bits that have been
705 buffered, but are less than the
706 BITNUM (usually set to 8) number of
707 bits)
708 0 - flush with zeros
709 1 - flush with ones
710 -1 - throw away any leftover bits
711 RETURNS
712 returns SUCCEED (0) if successful, FAIL (-1) otherwise
713 DESCRIPTION
714 Used to dispose of a bitfile element. Flushes any buffered bits
715 to the dataset (if writing), and then calls Hendaccess.
716 GLOBAL VARIABLES
717 COMMENTS, BUGS, ASSUMPTIONS
718 EXAMPLES
719 REVISION LOG
720 --------------------------------------------------------------------------*/
721 int32
Hendbitaccess(int32 bitfile_id,intn flushbit)722 Hendbitaccess(int32 bitfile_id, intn flushbit)
723 {
724 CONSTR(FUNC, "Hendbitaccess"); /* for HERROR */
725 bitrec_t *bitfile_rec; /* bitfile record */
726
727 /* check validity of access id */
728 bitfile_rec = HAatom_object(bitfile_id);
729 if (bitfile_rec == NULL)
730 HRETURN_ERROR(DFE_ARGS, FAIL);
731
732 if (bitfile_rec->mode == 'w')
733 if (HIbitflush(bitfile_rec, flushbit, TRUE) == FAIL)
734 HRETURN_ERROR(DFE_WRITEERROR,FAIL);
735 HDfree((VOIDP) bitfile_rec->bytea); /* free the space for the buffer */
736
737 if(HAremove_atom(bitfile_id)==NULL)
738 HRETURN_ERROR(DFE_WRITEERROR,FAIL);
739 if(Hendaccess(bitfile_rec->acc_id)==FAIL)
740 HRETURN_ERROR(DFE_CANTENDACCESS,FAIL);
741 HDfree(bitfile_rec);
742
743 return (SUCCEED);
744 } /* end Hendbitaccess() */
745
746 /*--------------------------------------------------------------------------
747 NAME
748 HIbitstart
749 PURPOSE
750 Bit I/O initialization routine
751 USAGE
752 intn HIbitstart()
753 RETURNS
754 Returns SUCCEED/FAIL
755 DESCRIPTION
756 One-time initialization of the interface
757 GLOBAL VARIABLES
758 COMMENTS, BUGS, ASSUMPTIONS
759 EXAMPLES
760 REVISION LOG
761 --------------------------------------------------------------------------*/
HIbitstart(void)762 PRIVATE intn HIbitstart(void)
763 {
764 CONSTR(FUNC, "HIbitstart"); /* for HERROR */
765 intn ret_value = SUCCEED;
766
767 /* Don't call this routine again... */
768 library_terminate = TRUE;
769
770 /* Create the file ID and access ID groups */
771 if(HAinit_group(BITIDGROUP,16)==FAIL)
772 HGOTO_ERROR(DFE_INTERNAL, FAIL);
773
774 done:
775 if(ret_value == FAIL)
776 { /* Error condition cleanup */
777
778 } /* end if */
779
780 /* Normal function cleanup */
781 return(ret_value);
782 } /* end HIbitstart() */
783
784 /*--------------------------------------------------------------------------
785
786 NAME
787 HIbitflush -- flush the bits out to a writable bitfile
788 USAGE
789 intn HIbitflush(bitfile_rec,flushbit)
790 bitrec_t *bitfile_rec; IN: record of bitfile element to flush
791 intn flushbit; IN: determines how to flush leftover bits
792 (leftover bits are bits that have been
793 buffered, but are less than the
794 BITNUM (usually set to 8) number of
795 bits)
796 0 - flush with zeros
797 1 - flush with ones
798 -1 - throw away any leftover bits
799 RETURNS
800 returns SUCCEED (0) if successful, FAIL (-1) otherwise
801 DESCRIPTION
802 Used to flush the buffer of a bitfile element, preserving the bits
803 in the buffer which have not been modified. The flushbits parameter
804 is only used when the last bits written to the element are at the
805 actual end of the dataset, not somewhere in the middle.
806 GLOBAL VARIABLES
807 COMMENTS, BUGS, ASSUMPTIONS
808 This routine does _not_ leave the bitfile in a position to continue
809 I/O from the current point, additional modifications would have to be
810 made in order to accomodate this.
811 EXAMPLES
812 REVISION LOG
813 --------------------------------------------------------------------------*/
814 PRIVATE intn
HIbitflush(bitrec_t * bitfile_rec,intn flushbit,intn writeout)815 HIbitflush(bitrec_t * bitfile_rec, intn flushbit, intn writeout)
816 {
817 CONSTR(FUNC, "HIbitflush");
818 intn write_size; /* number of bytes to write out */
819
820 if (bitfile_rec->count < (intn)BITNUM)
821 { /* check if there are any */
822 if (bitfile_rec->byte_offset > bitfile_rec->max_offset)
823 {
824 if (flushbit != (-1)) /* only flush bits if asked and there are bits to flush */
825 if (Hbitwrite(bitfile_rec->bit_id, bitfile_rec->count, (uint32) (flushbit ? 0xFF : 0)) == FAIL)
826 HRETURN_ERROR(DFE_WRITEERROR, FAIL);
827 } /* end if */
828 else
829 { /* we are in the middle of a dataset and need to integrate */
830 /* mask off a place for the new bits */
831 *(bitfile_rec->bytep) &= (uint8)(~(maskc[(intn)BITNUM - bitfile_rec->count] << bitfile_rec->count));
832
833 /* merge in new bits */
834 *(bitfile_rec->bytep) |= bitfile_rec->bits;
835
836 bitfile_rec->bytep++;
837 bitfile_rec->byte_offset++;
838
839 /* Update the offset in the buffer */
840 if (bitfile_rec->byte_offset > bitfile_rec->max_offset)
841 bitfile_rec->max_offset = bitfile_rec->byte_offset;
842
843 bitfile_rec->count = BITNUM; /* reset count */
844 bitfile_rec->bits=0; /* reset bits */
845 } /* end else */
846 } /* end if */
847 if (writeout == TRUE)
848 { /* only write data out if necessary */
849 write_size = (intn) MIN((bitfile_rec->bytez - bitfile_rec->bytea),bitfile_rec->max_offset);
850 if (write_size > 0)
851 if (Hwrite(bitfile_rec->acc_id, write_size, bitfile_rec->bytea) == FAIL)
852 HRETURN_ERROR(DFE_WRITEERROR, FAIL);
853 } /* end if */
854
855 return (SUCCEED);
856 } /* HIbitflush */
857
858 /*--------------------------------------------------------------------------
859 HIget_bitfile_rec - get a new bitfile record
860 --------------------------------------------------------------------------*/
861 PRIVATE bitrec_t *
HIget_bitfile_rec(void)862 HIget_bitfile_rec(void)
863 {
864 CONSTR(FUNC, "HIget_bitfile_rec");
865 bitrec_t *ret_value=NULL;
866
867 ret_value = (bitrec_t *) HDcalloc(1, sizeof(bitrec_t));
868 if ((ret_value->bytea = (uint8 *) HDmalloc(BITBUF_SIZE)) == NULL)
869 HRETURN_ERROR(DFE_NOSPACE, NULL);
870
871 return ret_value;
872 } /* HIget_bitfile_rec */
873
874 /*--------------------------------------------------------------------------
875
876 NAME
877 HIread2write - switch from reading bits to writing them
878 USAGE
879 intn HIread2write(bitfile_rec)
880 bitrec_t *bitfile_rec; IN: record of bitfile element to switch
881 RETURNS
882 returns SUCCEED (0) if successful, FAIL (-1) otherwise
883 DESCRIPTION
884 Used to switch a bitfile (which has 'w' access) from read mode to write
885 mode, at the same bit offset in the file.
886 GLOBAL VARIABLES
887 COMMENTS, BUGS, ASSUMPTIONS
888 EXAMPLES
889 REVISION LOG
890 --------------------------------------------------------------------------*/
891 PRIVATE intn
HIread2write(bitrec_t * bitfile_rec)892 HIread2write(bitrec_t * bitfile_rec)
893 {
894 CONSTR(FUNC, "HIread2write");
895
896 bitfile_rec->block_offset = (int32)LONG_MIN; /* set to bogus value */
897 bitfile_rec->mode = 'w'; /* change to write mode */
898 if (Hbitseek(bitfile_rec->bit_id, bitfile_rec->byte_offset, ((intn)BITNUM - bitfile_rec->count)) == FAIL)
899 HRETURN_ERROR(DFE_INTERNAL, FAIL);
900 return (SUCCEED);
901 } /* HIread2write */
902
903 /*--------------------------------------------------------------------------
904
905 NAME
906 HIwrite2read - switch from writing bits to reading them
907 USAGE
908 intn HIwrite2read(bitfile_rec)
909 bitrec_t *bitfile_rec; IN: record of bitfile element to switch
910 RETURNS
911 returns SUCCEED (0) if successful, FAIL (-1) otherwise
912 DESCRIPTION
913 Used to switch a bitfile (which has 'w' access) from write mode to read
914 mode, at the same bit offset in the file.
915 GLOBAL VARIABLES
916 COMMENTS, BUGS, ASSUMPTIONS
917 EXAMPLES
918 REVISION LOG
919 --------------------------------------------------------------------------*/
920 PRIVATE intn
HIwrite2read(bitrec_t * bitfile_rec)921 HIwrite2read(bitrec_t * bitfile_rec)
922 {
923 CONSTR(FUNC, "HIwrite2read");
924 intn prev_count = bitfile_rec->count; /* preserve this for later */
925 int32 prev_offset = bitfile_rec->byte_offset;
926
927 if (HIbitflush(bitfile_rec, -1, TRUE) == FAIL) /* flush any leftover bits */
928 HRETURN_ERROR(DFE_WRITEERROR, FAIL);
929
930 bitfile_rec->block_offset = (int32)LONG_MIN; /* set to bogus value */
931 bitfile_rec->mode = 'r'; /* change to read mode */
932 if (Hbitseek(bitfile_rec->bit_id, prev_offset, ((intn)BITNUM - prev_count)) == FAIL)
933 HRETURN_ERROR(DFE_INTERNAL, FAIL);
934 return (SUCCEED);
935 } /* HIwrite2read */
936
937 /*--------------------------------------------------------------------------
938 NAME
939 HPbitshutdown
940 PURPOSE
941 Terminate various static buffers.
942 USAGE
943 intn HPbitshutdown()
944 RETURNS
945 Returns SUCCEED/FAIL
946 DESCRIPTION
947 Free various buffers allocated in the Hbit routines.
948 GLOBAL VARIABLES
949 COMMENTS, BUGS, ASSUMPTIONS
950 Should only ever be called by the "atexit" function HDFend
951 EXAMPLES
952 REVISION LOG
953 --------------------------------------------------------------------------*/
HPbitshutdown(void)954 intn HPbitshutdown(void)
955 {
956 /* Shutdown the file ID atom group */
957 HAdestroy_group(BITIDGROUP);
958
959 return(SUCCEED);
960 } /* end HPbitshutdown() */
961
962