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