3 * Copyright (C) 2000-2002 A.J. van Os; Released under GPL
6 * Build, read and destroy a list of Word data blocks
19 * Private structure to hide the way the information
20 * is stored from the rest of the program
22 typedef struct data_mem_tag
{
23 data_block_type tInfo
;
24 struct data_mem_tag
*pNext
;
27 /* Variable to describe the start of the data block list */
28 static data_mem_type
*pAnchor
= NULL
;
29 /* Variable needed to read the data block list */
30 static data_mem_type
*pBlockLast
= NULL
;
31 /* Variable needed to read the data block list */
32 static data_mem_type
*pBlockCurrent
= NULL
;
33 static ULONG ulBlockOffset
= 0;
34 static size_t tByteNext
= 0;
36 static UCHAR aucBlock
[BIG_BLOCK_SIZE
];
40 * vDestroyDataBlockList - destroy the data block list
43 vDestroyDataBlockList(void)
45 data_mem_type
*pCurr
, *pNext
;
47 DBG_MSG("vDestroyDataBlockList");
50 while (pCurr
!= NULL
) {
56 /* Reset all the control variables */
61 } /* end of vDestroyDataBlockList */
64 * bAdd2DataBlockList - add an element to the data block list
66 * Returns TRUE when successful, otherwise FALSE
69 bAdd2DataBlockList(const data_block_type
*pDataBlock
)
71 data_mem_type
*pListMember
;
73 fail(pDataBlock
== NULL
);
74 fail(pDataBlock
->ulFileOffset
== FC_INVALID
);
75 fail(pDataBlock
->ulDataPos
== CP_INVALID
);
76 fail(pDataBlock
->ulLength
== 0);
78 NO_DBG_MSG("bAdd2DataBlockList");
79 NO_DBG_HEX(pDataBlock
->ulFileOffset
);
80 NO_DBG_HEX(pDataBlock
->ulDataPos
);
81 NO_DBG_HEX(pDataBlock
->ulLength
);
83 if (pDataBlock
->ulFileOffset
== FC_INVALID
||
84 pDataBlock
->ulDataPos
== CP_INVALID
||
85 pDataBlock
->ulLength
== 0) {
86 werr(0, "Software (datablock) error");
89 /* Check for continuous blocks */
90 if (pBlockLast
!= NULL
&&
91 pBlockLast
->tInfo
.ulFileOffset
+
92 pBlockLast
->tInfo
.ulLength
== pDataBlock
->ulFileOffset
&&
93 pBlockLast
->tInfo
.ulDataPos
+
94 pBlockLast
->tInfo
.ulLength
== pDataBlock
->ulDataPos
) {
95 /* These are continous blocks */
96 pBlockLast
->tInfo
.ulLength
+= pDataBlock
->ulLength
;
99 /* Make a new block */
100 pListMember
= xmalloc(sizeof(data_mem_type
));
101 /* Add the block to the data list */
102 pListMember
->tInfo
= *pDataBlock
;
103 pListMember
->pNext
= NULL
;
104 if (pAnchor
== NULL
) {
105 pAnchor
= pListMember
;
107 fail(pBlockLast
== NULL
);
108 pBlockLast
->pNext
= pListMember
;
110 pBlockLast
= pListMember
;
112 } /* end of bAdd2DataBlockList */
115 * ulGetDataOffset - get the offset in the data block list
117 * Get the fileoffset the current position in the data block list
120 ulGetDataOffset(FILE *pFile
)
122 return pBlockCurrent
->tInfo
.ulFileOffset
+ ulBlockOffset
+ tByteNext
;
123 } /* end of ulGetDataOffset */
126 * bSetDataOffset - set the offset in the data block list
128 * Make the given fileoffset the current position in the data block list
131 bSetDataOffset(FILE *pFile
, ULONG ulFileOffset
)
133 data_mem_type
*pCurr
;
136 DBG_HEX(ulFileOffset
);
138 for (pCurr
= pAnchor
; pCurr
!= NULL
; pCurr
= pCurr
->pNext
) {
139 if (ulFileOffset
< pCurr
->tInfo
.ulFileOffset
||
140 ulFileOffset
>= pCurr
->tInfo
.ulFileOffset
+
141 pCurr
->tInfo
.ulLength
) {
142 /* The file offset is not in this block */
145 /* Compute the maximum number of bytes to read */
146 tReadLen
= (size_t)(pCurr
->tInfo
.ulFileOffset
+
147 pCurr
->tInfo
.ulLength
-
149 /* Compute the real number of bytes to read */
150 if (tReadLen
> sizeof(aucBlock
)) {
151 tReadLen
= sizeof(aucBlock
);
154 if (!bReadBytes(aucBlock
, tReadLen
, ulFileOffset
, pFile
)) {
157 /* Set the control variables */
158 pBlockCurrent
= pCurr
;
159 ulBlockOffset
= ulFileOffset
- pCurr
->tInfo
.ulFileOffset
;
164 } /* end of bSetDataOffset */
167 * iNextByte - get the next byte from the data block list
170 iNextByte(FILE *pFile
)
175 fail(pBlockCurrent
== NULL
);
177 if (tByteNext
>= sizeof(aucBlock
) ||
178 ulBlockOffset
+ tByteNext
>= pBlockCurrent
->tInfo
.ulLength
) {
179 if (ulBlockOffset
+ sizeof(aucBlock
) <
180 pBlockCurrent
->tInfo
.ulLength
) {
181 /* Same block, next part */
182 ulBlockOffset
+= sizeof(aucBlock
);
184 /* Next block, first part */
185 pBlockCurrent
= pBlockCurrent
->pNext
;
188 if (pBlockCurrent
== NULL
) {
189 /* Past the last part of the last block */
194 (pBlockCurrent
->tInfo
.ulLength
- ulBlockOffset
);
195 if (tReadLen
> sizeof(aucBlock
)) {
196 tReadLen
= sizeof(aucBlock
);
198 ulReadOff
= pBlockCurrent
->tInfo
.ulFileOffset
+ ulBlockOffset
;
199 if (!bReadBytes(aucBlock
, tReadLen
, ulReadOff
, pFile
)) {
205 return (int)aucBlock
[tByteNext
++];
206 } /* end of iNextByte */
209 * usNextWord - get the next word from the data block list
211 * Read a two byte value in Little Endian order, that means MSB last
213 * All return values can be valid so errno is set in case of error
216 usNextWord(FILE *pFile
)
220 usLSB
= (USHORT
)iNextByte(pFile
);
221 if (usLSB
== (USHORT
)EOF
) {
225 usMSB
= (USHORT
)iNextByte(pFile
);
226 if (usMSB
== (USHORT
)EOF
) {
227 DBG_MSG("usNextWord: Unexpected EOF");
231 return (usMSB
<< 8) | usLSB
;
232 } /* end of usNextWord */
235 * ulNextLong - get the next long from the data block list
237 * Read a four byte value in Little Endian order, that means MSW last
239 * All return values can be valid so errno is set in case of error
242 ulNextLong(FILE *pFile
)
246 ulLSW
= (ULONG
)usNextWord(pFile
);
247 if (ulLSW
== (ULONG
)EOF
) {
251 ulMSW
= (ULONG
)usNextWord(pFile
);
252 if (ulMSW
== (ULONG
)EOF
) {
253 DBG_MSG("ulNextLong: Unexpected EOF");
257 return (ulMSW
<< 16) | ulLSW
;
258 } /* end of ulNextLong */
261 * usNextWordBE - get the next two byte value
263 * Read a two byte value in Big Endian order, that means MSB first
265 * All return values can be valid so errno is set in case of error
268 usNextWordBE(FILE *pFile
)
272 usMSB
= (USHORT
)iNextByte(pFile
);
273 if (usMSB
== (USHORT
)EOF
) {
277 usLSB
= (USHORT
)iNextByte(pFile
);
278 if (usLSB
== (USHORT
)EOF
) {
279 DBG_MSG("usNextWordBE: Unexpected EOF");
283 return (usMSB
<< 8) | usLSB
;
284 } /* end of usNextWordBE */
287 * ulNextLongBE - get the next four byte value
289 * Read a four byte value in Big Endian order, that means MSW first
291 * All return values can be valid so errno is set in case of error
294 ulNextLongBE(FILE *pFile
)
298 ulMSW
= (ULONG
)usNextWordBE(pFile
);
299 if (ulMSW
== (ULONG
)EOF
) {
303 ulLSW
= (ULONG
)usNextWordBE(pFile
);
304 if (ulLSW
== (ULONG
)EOF
) {
305 DBG_MSG("ulNextLongBE: Unexpected EOF");
309 return (ulMSW
<< 16) | ulLSW
;
310 } /* end of ulNextLongBE */
313 * tSkipBytes - skip over the given number of bytes
315 * Returns the number of skipped bytes
318 tSkipBytes(FILE *pFile
, size_t tToSkip
)
320 size_t tToGo
, tMaxMove
, tMove
;
323 fail(pBlockCurrent
== NULL
);
327 /* Goto the end of the current block */
328 tMaxMove
= min(sizeof(aucBlock
) - tByteNext
,
329 (size_t)(pBlockCurrent
->tInfo
.ulLength
-
330 ulBlockOffset
- tByteNext
));
331 tMove
= min(tMaxMove
, tToGo
);
335 /* Goto the next block */
336 if (iNextByte(pFile
) == EOF
) {
337 return tToSkip
- tToGo
;
343 } /* end of tSkipBytes */
346 * Translate a data position to an offset in the file.
347 * Logical to physical offset.
349 * Returns: FC_INVALID: in case of error
350 * otherwise: the computed file offset
353 ulDataPos2FileOffset(ULONG ulDataPos
)
355 data_mem_type
*pCurr
;
357 fail(ulDataPos
== CP_INVALID
);
359 for (pCurr
= pAnchor
; pCurr
!= NULL
; pCurr
= pCurr
->pNext
) {
360 if (ulDataPos
< pCurr
->tInfo
.ulDataPos
||
361 ulDataPos
>= pCurr
->tInfo
.ulDataPos
+
362 pCurr
->tInfo
.ulLength
) {
363 /* The data offset is not in this block, try the next */
366 /* The data offset is in the current block */
367 return pCurr
->tInfo
.ulFileOffset
+
369 pCurr
->tInfo
.ulDataPos
;
371 /* Passed beyond the end of the list */
372 DBG_HEX_C(ulDataPos
!= 0, ulDataPos
);
374 } /* end of ulDataPos2FileOffset */