1 /***************************************************************************
2 *
3 * Routines to parse Mini-SEED.
4 *
5 * Written by Chad Trabant
6 * IRIS Data Management Center
7 *
8 * modified: 2015.108
9 ***************************************************************************/
10
11 #include <errno.h>
12 #include <stdio.h>
13 #include <stdlib.h>
14 #include <string.h>
15 #include <time.h>
16
17 #include "libmseed.h"
18
19 /**********************************************************************
20 * msr_parse:
21 *
22 * This routine will attempt to parse (detect and unpack) a Mini-SEED
23 * record from a specified memory buffer and populate a supplied
24 * MSRecord structure.
25 *
26 * If reclen is less than or equal to 0 the length of record is
27 * automatically detected otherwise reclen should be the correct
28 * record length.
29 *
30 * For auto detection of record length the record should include a
31 * 1000 blockette or be followed by another record header in the
32 * buffer.
33 *
34 * dataflag will be passed directly to msr_unpack().
35 *
36 * Return values:
37 * 0 : Success, populates the supplied MSRecord.
38 * >0 : Data record detected but not enough data is present, the
39 * return value is a hint of how many more bytes are needed.
40 * <0 : libmseed error code (listed in libmseed.h) is returned.
41 *********************************************************************/
42 int
msr_parse(char * record,int recbuflen,MSRecord ** ppmsr,int reclen,flag dataflag,flag verbose)43 msr_parse (char *record, int recbuflen, MSRecord **ppmsr, int reclen,
44 flag dataflag, flag verbose)
45 {
46 int detlen = 0;
47 int retcode = 0;
48
49 if (!ppmsr)
50 return MS_GENERROR;
51
52 if (!record)
53 return MS_GENERROR;
54
55 /* Sanity check: record length cannot be larger than buffer */
56 if (reclen > 0 && reclen > recbuflen)
57 {
58 ms_log (2, "ms_parse() Record length (%d) cannot be larger than buffer (%d)\n",
59 reclen, recbuflen);
60 return MS_GENERROR;
61 }
62
63 /* Autodetect the record length */
64 if (reclen <= 0)
65 {
66 detlen = ms_detect (record, recbuflen);
67
68 /* No data record detected */
69 if (detlen < 0)
70 {
71 return MS_NOTSEED;
72 }
73
74 /* Found record but could not determine length */
75 if (detlen == 0)
76 {
77 return MINRECLEN;
78 }
79
80 if (verbose > 2)
81 {
82 ms_log (1, "Detected record length of %d bytes\n", detlen);
83 }
84
85 reclen = detlen;
86 }
87
88 /* Check that record length is in supported range */
89 if (reclen < MINRECLEN || reclen > MAXRECLEN)
90 {
91 ms_log (2, "Record length is out of range: %d (allowed: %d to %d)\n",
92 reclen, MINRECLEN, MAXRECLEN);
93
94 return MS_OUTOFRANGE;
95 }
96
97 /* Check if more data is required, return hint */
98 if (reclen > recbuflen)
99 {
100 if (verbose > 2)
101 ms_log (1, "Detected %d byte record, need %d more bytes\n",
102 reclen, (reclen - recbuflen));
103
104 return (reclen - recbuflen);
105 }
106
107 /* Unpack record */
108 if ((retcode = msr_unpack (record, reclen, ppmsr, dataflag, verbose)) != MS_NOERROR)
109 {
110 msr_free (ppmsr);
111
112 return retcode;
113 }
114
115 return MS_NOERROR;
116 } /* End of msr_parse() */
117
118 /**********************************************************************
119 * msr_parse_selection:
120 *
121 * This routine wraps msr_parse() to parse and return the first record
122 * from a memory buffer that matches optional Selections. If the
123 * selections pointer is NULL the effect is to search the buffer for
124 * the first parsable record.
125 *
126 * The offset value specifies the starting offset in the buffer and,
127 * on success, the offset in the buffer to record parsed.
128 *
129 * The caller should manage the value of the offset in two ways:
130 *
131 * 1) on subsequent calls after a record has been parsed the caller
132 * should increment the offset by the record length returned or
133 * properly manipulate the record buffer pointer, buffer length and
134 * offset to the same effect.
135 *
136 * 2) when the end of the buffer is reached MS_GENERROR (-1) is
137 * returned, the caller should check the offset value against the
138 * record buffer length to determine when the entire buffer has been
139 * searched.
140 *
141 * Return values: same as msr_parse() except that MS_GENERROR is
142 * returned when end-of-buffer is reached.
143 *********************************************************************/
144 int
msr_parse_selection(char * recbuf,int recbuflen,int64_t * offset,MSRecord ** ppmsr,int reclen,Selections * selections,flag dataflag,flag verbose)145 msr_parse_selection (char *recbuf, int recbuflen, int64_t *offset,
146 MSRecord **ppmsr, int reclen,
147 Selections *selections, flag dataflag, flag verbose)
148 {
149 int retval = MS_GENERROR;
150 int unpackretval;
151 flag dataswapflag = 0;
152 flag bigendianhost = ms_bigendianhost ();
153
154 if (!ppmsr)
155 return MS_GENERROR;
156
157 if (!recbuf)
158 return MS_GENERROR;
159
160 if (!offset)
161 return MS_GENERROR;
162
163 while (*offset < recbuflen)
164 {
165 retval = msr_parse (recbuf + *offset, (int)(recbuflen - *offset), ppmsr, reclen, 0, verbose);
166
167 if (retval)
168 {
169 if (verbose)
170 ms_log (2, "Error parsing record at offset %" PRId64 "\n", *offset);
171
172 *offset += MINRECLEN;
173 }
174 else
175 {
176 if (selections && !msr_matchselect (selections, *ppmsr, NULL))
177 {
178 *offset += (*ppmsr)->reclen;
179 retval = MS_GENERROR;
180 }
181 else
182 {
183 if (dataflag)
184 {
185 /* If BE host and LE data need swapping */
186 if (bigendianhost && (*ppmsr)->byteorder == 0)
187 dataswapflag = 1;
188 /* If LE host and BE data (or bad byte order value) need swapping */
189 else if (!bigendianhost && (*ppmsr)->byteorder > 0)
190 dataswapflag = 1;
191
192 unpackretval = msr_unpack_data (*ppmsr, dataswapflag, verbose);
193
194 if (unpackretval < 0)
195 return unpackretval;
196 else
197 (*ppmsr)->numsamples = unpackretval;
198 }
199
200 break;
201 }
202 }
203 }
204
205 return retval;
206 } /* End of msr_parse_selection() */
207
208 /********************************************************************
209 * ms_detect:
210 *
211 * Determine SEED data record length with the following steps:
212 *
213 * 1) determine that the buffer contains a SEED data record by
214 * verifying known signatures (fields with known limited values)
215 *
216 * 2) search the record up to recbuflen bytes for a 1000 blockette.
217 *
218 * 3) If no blockette 1000 is found search at MINRECLEN-byte offsets
219 * for the fixed section of the next header or blank/noise record,
220 * thereby implying the record length.
221 *
222 * Returns:
223 * -1 : data record not detected or error
224 * 0 : data record detected but could not determine length
225 * >0 : size of the record in bytes
226 *********************************************************************/
227 int
ms_detect(const char * record,int recbuflen)228 ms_detect (const char *record, int recbuflen)
229 {
230 uint16_t blkt_offset; /* Byte offset for next blockette */
231 uint8_t swapflag = 0; /* Byte swapping flag */
232 uint8_t foundlen = 0; /* Found record length */
233 int32_t reclen = -1; /* Size of record in bytes */
234
235 uint16_t blkt_type;
236 uint16_t next_blkt;
237
238 struct fsdh_s *fsdh;
239 struct blkt_1000_s *blkt_1000;
240 const char *nextfsdh;
241
242 /* Buffer must be at least 48 bytes (the fixed section) */
243 if (recbuflen < 48)
244 return -1;
245
246 /* Check for valid fixed section of header */
247 if (!MS_ISVALIDHEADER (record))
248 return -1;
249
250 fsdh = (struct fsdh_s *)record;
251
252 /* Check to see if byte swapping is needed by checking for sane year and day */
253 if (!MS_ISVALIDYEARDAY (fsdh->start_time.year, fsdh->start_time.day))
254 swapflag = 1;
255
256 blkt_offset = fsdh->blockette_offset;
257
258 /* Swap order of blkt_offset if needed */
259 if (swapflag)
260 ms_gswap2 (&blkt_offset);
261
262 /* Loop through blockettes as long as number is non-zero and viable */
263 while (blkt_offset != 0 &&
264 blkt_offset <= recbuflen)
265 {
266 memcpy (&blkt_type, record + blkt_offset, 2);
267 memcpy (&next_blkt, record + blkt_offset + 2, 2);
268
269 if (swapflag)
270 {
271 ms_gswap2 (&blkt_type);
272 ms_gswap2 (&next_blkt);
273 }
274
275 /* Found a 1000 blockette, not truncated */
276 if (blkt_type == 1000 &&
277 (int)(blkt_offset + 4 + sizeof (struct blkt_1000_s)) <= recbuflen)
278 {
279 blkt_1000 = (struct blkt_1000_s *)(record + blkt_offset + 4);
280
281 foundlen = 1;
282
283 /* Calculate record size in bytes as 2^(blkt_1000->reclen) */
284 reclen = (unsigned int)1 << blkt_1000->reclen;
285
286 break;
287 }
288
289 /* Safety check for invalid offset */
290 if (next_blkt != 0 && (next_blkt < 4 || (next_blkt - 4) <= blkt_offset))
291 {
292 ms_log (2, "Invalid blockette offset (%d) less than or equal to current offset (%d)\n",
293 next_blkt, blkt_offset);
294 return -1;
295 }
296
297 blkt_offset = next_blkt;
298 }
299
300 /* If record length was not determined by a 1000 blockette scan the buffer
301 * and search for the next record */
302 if (reclen == -1)
303 {
304 nextfsdh = record + MINRECLEN;
305
306 /* Check for record header or blank/noise record at MINRECLEN byte offsets */
307 while (((nextfsdh - record) + 48) < recbuflen)
308 {
309 if (MS_ISVALIDHEADER (nextfsdh) || MS_ISVALIDBLANK (nextfsdh))
310 {
311 foundlen = 1;
312 reclen = nextfsdh - record;
313 break;
314 }
315
316 nextfsdh += MINRECLEN;
317 }
318 }
319
320 if (!foundlen)
321 return 0;
322 else
323 return reclen;
324 } /* End of ms_detect() */
325
326 /***************************************************************************
327 * ms_parse_raw:
328 *
329 * Parse and verify a SEED data record header (fixed section and
330 * blockettes) at the lowest level, printing error messages for
331 * invalid header values and optionally print raw header values. The
332 * memory at 'record' is assumed to be a Mini-SEED record. Not every
333 * possible test is performed, common errors and those causing
334 * libmseed parsing to fail should be detected.
335 *
336 * The 'details' argument is interpreted as follows:
337 *
338 * details:
339 * 0 = only print error messages for invalid header fields
340 * 1 = print basic fields in addition to invalid field errors
341 * 2 = print all fields in addition to invalid field errors
342 *
343 * The 'swapflag' argument is interpreted as follows:
344 *
345 * swapflag:
346 * 1 = swap multibyte quantities
347 * 0 = do no swapping
348 * -1 = autodetect byte order using year test, swap if needed
349 *
350 * Any byte swapping performed by this routine is applied directly to
351 * the memory reference by the record pointer.
352 *
353 * This routine is primarily intended to diagnose invalid Mini-SEED headers.
354 *
355 * Returns 0 when no errors were detected or a positive count of
356 * errors detected.
357 ***************************************************************************/
358 int
ms_parse_raw(char * record,int maxreclen,flag details,flag swapflag)359 ms_parse_raw (char *record, int maxreclen, flag details, flag swapflag)
360 {
361 struct fsdh_s *fsdh;
362 double nomsamprate;
363 char srcname[50];
364 char *X;
365 char b;
366 int retval = 0;
367 int b1000encoding = -1;
368 int b1000reclen = -1;
369 int endofblockettes = -1;
370 int idx;
371
372 if (!record)
373 return 1;
374
375 /* Generate a source name string */
376 srcname[0] = '\0';
377 ms_recsrcname (record, srcname, 1);
378
379 fsdh = (struct fsdh_s *)record;
380
381 /* Check to see if byte swapping is needed by testing the year and day */
382 if (swapflag == -1 && !MS_ISVALIDYEARDAY (fsdh->start_time.year, fsdh->start_time.day))
383 swapflag = 1;
384 else
385 swapflag = 0;
386
387 if (details > 1)
388 {
389 if (swapflag == 1)
390 ms_log (0, "Swapping multi-byte quantities in header\n");
391 else
392 ms_log (0, "Not swapping multi-byte quantities in header\n");
393 }
394
395 /* Swap byte order */
396 if (swapflag)
397 {
398 MS_SWAPBTIME (&fsdh->start_time);
399 ms_gswap2a (&fsdh->numsamples);
400 ms_gswap2a (&fsdh->samprate_fact);
401 ms_gswap2a (&fsdh->samprate_mult);
402 ms_gswap4a (&fsdh->time_correct);
403 ms_gswap2a (&fsdh->data_offset);
404 ms_gswap2a (&fsdh->blockette_offset);
405 }
406
407 /* Validate fixed section header fields */
408 X = record; /* Pointer of convenience */
409
410 /* Check record sequence number, 6 ASCII digits */
411 if (!isdigit ((int)*(X)) || !isdigit ((int)*(X + 1)) ||
412 !isdigit ((int)*(X + 2)) || !isdigit ((int)*(X + 3)) ||
413 !isdigit ((int)*(X + 4)) || !isdigit ((int)*(X + 5)))
414 {
415 ms_log (2, "%s: Invalid sequence number: '%c%c%c%c%c%c'\n", srcname, X, X + 1, X + 2, X + 3, X + 4, X + 5);
416 retval++;
417 }
418
419 /* Check header/quality indicator */
420 if (!MS_ISDATAINDICATOR (*(X + 6)))
421 {
422 ms_log (2, "%s: Invalid header indicator (DRQM): '%c'\n", srcname, X + 6);
423 retval++;
424 }
425
426 /* Check reserved byte, space or NULL */
427 if (!(*(X + 7) == ' ' || *(X + 7) == '\0'))
428 {
429 ms_log (2, "%s: Invalid fixed section reserved byte (Space): '%c'\n", srcname, X + 7);
430 retval++;
431 }
432
433 /* Check station code, 5 alphanumerics or spaces */
434 if (!(isalnum ((unsigned char)*(X + 8)) || *(X + 8) == ' ') ||
435 !(isalnum ((unsigned char)*(X + 9)) || *(X + 9) == ' ') ||
436 !(isalnum ((unsigned char)*(X + 10)) || *(X + 10) == ' ') ||
437 !(isalnum ((unsigned char)*(X + 11)) || *(X + 11) == ' ') ||
438 !(isalnum ((unsigned char)*(X + 12)) || *(X + 12) == ' '))
439 {
440 ms_log (2, "%s: Invalid station code: '%c%c%c%c%c'\n", srcname, X + 8, X + 9, X + 10, X + 11, X + 12);
441 retval++;
442 }
443
444 /* Check location ID, 2 alphanumerics or spaces */
445 if (!(isalnum ((unsigned char)*(X + 13)) || *(X + 13) == ' ') ||
446 !(isalnum ((unsigned char)*(X + 14)) || *(X + 14) == ' '))
447 {
448 ms_log (2, "%s: Invalid location ID: '%c%c'\n", srcname, X + 13, X + 14);
449 retval++;
450 }
451
452 /* Check channel codes, 3 alphanumerics or spaces */
453 if (!(isalnum ((unsigned char)*(X + 15)) || *(X + 15) == ' ') ||
454 !(isalnum ((unsigned char)*(X + 16)) || *(X + 16) == ' ') ||
455 !(isalnum ((unsigned char)*(X + 17)) || *(X + 17) == ' '))
456 {
457 ms_log (2, "%s: Invalid channel codes: '%c%c%c'\n", srcname, X + 15, X + 16, X + 17);
458 retval++;
459 }
460
461 /* Check network code, 2 alphanumerics or spaces */
462 if (!(isalnum ((unsigned char)*(X + 18)) || *(X + 18) == ' ') ||
463 !(isalnum ((unsigned char)*(X + 19)) || *(X + 19) == ' '))
464 {
465 ms_log (2, "%s: Invalid network code: '%c%c'\n", srcname, X + 18, X + 19);
466 retval++;
467 }
468
469 /* Check start time fields */
470 if (fsdh->start_time.year < 1900 || fsdh->start_time.year > 2100)
471 {
472 ms_log (2, "%s: Unlikely start year (1900-2100): '%d'\n", srcname, fsdh->start_time.year);
473 retval++;
474 }
475 if (fsdh->start_time.day < 1 || fsdh->start_time.day > 366)
476 {
477 ms_log (2, "%s: Invalid start day (1-366): '%d'\n", srcname, fsdh->start_time.day);
478 retval++;
479 }
480 if (fsdh->start_time.hour > 23)
481 {
482 ms_log (2, "%s: Invalid start hour (0-23): '%d'\n", srcname, fsdh->start_time.hour);
483 retval++;
484 }
485 if (fsdh->start_time.min > 59)
486 {
487 ms_log (2, "%s: Invalid start minute (0-59): '%d'\n", srcname, fsdh->start_time.min);
488 retval++;
489 }
490 if (fsdh->start_time.sec > 60)
491 {
492 ms_log (2, "%s: Invalid start second (0-60): '%d'\n", srcname, fsdh->start_time.sec);
493 retval++;
494 }
495 if (fsdh->start_time.fract > 9999)
496 {
497 ms_log (2, "%s: Invalid start fractional seconds (0-9999): '%d'\n", srcname, fsdh->start_time.fract);
498 retval++;
499 }
500
501 /* Check number of samples, max samples in 4096-byte Steim-2 encoded record: 6601 */
502 if (fsdh->numsamples > 20000)
503 {
504 ms_log (2, "%s: Unlikely number of samples (>20000): '%d'\n", srcname, fsdh->numsamples);
505 retval++;
506 }
507
508 /* Sanity check that there is space for blockettes when both data and blockettes are present */
509 if (fsdh->numsamples > 0 && fsdh->numblockettes > 0 && fsdh->data_offset <= fsdh->blockette_offset)
510 {
511 ms_log (2, "%s: No space for %d blockettes, data offset: %d, blockette offset: %d\n", srcname,
512 fsdh->numblockettes, fsdh->data_offset, fsdh->blockette_offset);
513 retval++;
514 }
515
516 /* Print raw header details */
517 if (details >= 1)
518 {
519 /* Determine nominal sample rate */
520 nomsamprate = ms_nomsamprate (fsdh->samprate_fact, fsdh->samprate_mult);
521
522 /* Print header values */
523 ms_log (0, "RECORD -- %s\n", srcname);
524 ms_log (0, " sequence number: '%c%c%c%c%c%c'\n", fsdh->sequence_number[0], fsdh->sequence_number[1], fsdh->sequence_number[2],
525 fsdh->sequence_number[3], fsdh->sequence_number[4], fsdh->sequence_number[5]);
526 ms_log (0, " data quality indicator: '%c'\n", fsdh->dataquality);
527 if (details > 0)
528 ms_log (0, " reserved: '%c'\n", fsdh->reserved);
529 ms_log (0, " station code: '%c%c%c%c%c'\n", fsdh->station[0], fsdh->station[1], fsdh->station[2], fsdh->station[3], fsdh->station[4]);
530 ms_log (0, " location ID: '%c%c'\n", fsdh->location[0], fsdh->location[1]);
531 ms_log (0, " channel codes: '%c%c%c'\n", fsdh->channel[0], fsdh->channel[1], fsdh->channel[2]);
532 ms_log (0, " network code: '%c%c'\n", fsdh->network[0], fsdh->network[1]);
533 ms_log (0, " start time: %d,%d,%d:%d:%d.%04d (unused: %d)\n", fsdh->start_time.year, fsdh->start_time.day,
534 fsdh->start_time.hour, fsdh->start_time.min, fsdh->start_time.sec, fsdh->start_time.fract, fsdh->start_time.unused);
535 ms_log (0, " number of samples: %d\n", fsdh->numsamples);
536 ms_log (0, " sample rate factor: %d (%.10g samples per second)\n",
537 fsdh->samprate_fact, nomsamprate);
538 ms_log (0, " sample rate multiplier: %d\n", fsdh->samprate_mult);
539
540 /* Print flag details if requested */
541 if (details > 1)
542 {
543 /* Activity flags */
544 b = fsdh->act_flags;
545 ms_log (0, " activity flags: [%u%u%u%u%u%u%u%u] 8 bits\n",
546 bit (b, 0x01), bit (b, 0x02), bit (b, 0x04), bit (b, 0x08),
547 bit (b, 0x10), bit (b, 0x20), bit (b, 0x40), bit (b, 0x80));
548 if (b & 0x01)
549 ms_log (0, " [Bit 0] Calibration signals present\n");
550 if (b & 0x02)
551 ms_log (0, " [Bit 1] Time correction applied\n");
552 if (b & 0x04)
553 ms_log (0, " [Bit 2] Beginning of an event, station trigger\n");
554 if (b & 0x08)
555 ms_log (0, " [Bit 3] End of an event, station detrigger\n");
556 if (b & 0x10)
557 ms_log (0, " [Bit 4] A positive leap second happened in this record\n");
558 if (b & 0x20)
559 ms_log (0, " [Bit 5] A negative leap second happened in this record\n");
560 if (b & 0x40)
561 ms_log (0, " [Bit 6] Event in progress\n");
562 if (b & 0x80)
563 ms_log (0, " [Bit 7] Undefined bit set\n");
564
565 /* I/O and clock flags */
566 b = fsdh->io_flags;
567 ms_log (0, " I/O and clock flags: [%u%u%u%u%u%u%u%u] 8 bits\n",
568 bit (b, 0x01), bit (b, 0x02), bit (b, 0x04), bit (b, 0x08),
569 bit (b, 0x10), bit (b, 0x20), bit (b, 0x40), bit (b, 0x80));
570 if (b & 0x01)
571 ms_log (0, " [Bit 0] Station volume parity error possibly present\n");
572 if (b & 0x02)
573 ms_log (0, " [Bit 1] Long record read (possibly no problem)\n");
574 if (b & 0x04)
575 ms_log (0, " [Bit 2] Short record read (record padded)\n");
576 if (b & 0x08)
577 ms_log (0, " [Bit 3] Start of time series\n");
578 if (b & 0x10)
579 ms_log (0, " [Bit 4] End of time series\n");
580 if (b & 0x20)
581 ms_log (0, " [Bit 5] Clock locked\n");
582 if (b & 0x40)
583 ms_log (0, " [Bit 6] Undefined bit set\n");
584 if (b & 0x80)
585 ms_log (0, " [Bit 7] Undefined bit set\n");
586
587 /* Data quality flags */
588 b = fsdh->dq_flags;
589 ms_log (0, " data quality flags: [%u%u%u%u%u%u%u%u] 8 bits\n",
590 bit (b, 0x01), bit (b, 0x02), bit (b, 0x04), bit (b, 0x08),
591 bit (b, 0x10), bit (b, 0x20), bit (b, 0x40), bit (b, 0x80));
592 if (b & 0x01)
593 ms_log (0, " [Bit 0] Amplifier saturation detected\n");
594 if (b & 0x02)
595 ms_log (0, " [Bit 1] Digitizer clipping detected\n");
596 if (b & 0x04)
597 ms_log (0, " [Bit 2] Spikes detected\n");
598 if (b & 0x08)
599 ms_log (0, " [Bit 3] Glitches detected\n");
600 if (b & 0x10)
601 ms_log (0, " [Bit 4] Missing/padded data present\n");
602 if (b & 0x20)
603 ms_log (0, " [Bit 5] Telemetry synchronization error\n");
604 if (b & 0x40)
605 ms_log (0, " [Bit 6] A digital filter may be charging\n");
606 if (b & 0x80)
607 ms_log (0, " [Bit 7] Time tag is questionable\n");
608 }
609
610 ms_log (0, " number of blockettes: %d\n", fsdh->numblockettes);
611 ms_log (0, " time correction: %ld\n", (long int)fsdh->time_correct);
612 ms_log (0, " data offset: %d\n", fsdh->data_offset);
613 ms_log (0, " first blockette offset: %d\n", fsdh->blockette_offset);
614 } /* Done printing raw header details */
615
616 /* Validate and report information in the blockette chain */
617 if (fsdh->blockette_offset > 46 && fsdh->blockette_offset < maxreclen)
618 {
619 int blkt_offset = fsdh->blockette_offset;
620 int blkt_count = 0;
621 int blkt_length;
622 uint16_t blkt_type;
623 uint16_t next_blkt;
624 char *blkt_desc;
625
626 /* Traverse blockette chain */
627 while (blkt_offset != 0 && blkt_offset < maxreclen)
628 {
629 /* Every blockette has a similar 4 byte header: type and next */
630 memcpy (&blkt_type, record + blkt_offset, 2);
631 memcpy (&next_blkt, record + blkt_offset + 2, 2);
632
633 if (swapflag)
634 {
635 ms_gswap2 (&blkt_type);
636 ms_gswap2 (&next_blkt);
637 }
638
639 /* Print common header fields */
640 if (details >= 1)
641 {
642 blkt_desc = ms_blktdesc (blkt_type);
643 ms_log (0, " BLOCKETTE %u: (%s)\n", blkt_type, (blkt_desc) ? blkt_desc : "Unknown");
644 ms_log (0, " next blockette: %u\n", next_blkt);
645 }
646
647 blkt_length = ms_blktlen (blkt_type, record + blkt_offset, swapflag);
648 if (blkt_length == 0)
649 {
650 ms_log (2, "%s: Unknown blockette length for type %d\n", srcname, blkt_type);
651 retval++;
652 }
653
654 /* Track end of blockette chain */
655 endofblockettes = blkt_offset + blkt_length - 1;
656
657 /* Sanity check that the blockette is contained in the record */
658 if (endofblockettes > maxreclen)
659 {
660 ms_log (2, "%s: Blockette type %d at offset %d with length %d does not fix in record (%d)\n",
661 srcname, blkt_type, blkt_offset, blkt_length, maxreclen);
662 retval++;
663 break;
664 }
665
666 if (blkt_type == 100)
667 {
668 struct blkt_100_s *blkt_100 = (struct blkt_100_s *)(record + blkt_offset + 4);
669
670 if (swapflag)
671 ms_gswap4 (&blkt_100->samprate);
672
673 if (details >= 1)
674 {
675 ms_log (0, " actual sample rate: %.10g\n", blkt_100->samprate);
676
677 if (details > 1)
678 {
679 b = blkt_100->flags;
680 ms_log (0, " undefined flags: [%u%u%u%u%u%u%u%u] 8 bits\n",
681 bit (b, 0x01), bit (b, 0x02), bit (b, 0x04), bit (b, 0x08),
682 bit (b, 0x10), bit (b, 0x20), bit (b, 0x40), bit (b, 0x80));
683
684 ms_log (0, " reserved bytes (3): %u,%u,%u\n",
685 blkt_100->reserved[0], blkt_100->reserved[1], blkt_100->reserved[2]);
686 }
687 }
688 }
689
690 else if (blkt_type == 200)
691 {
692 struct blkt_200_s *blkt_200 = (struct blkt_200_s *)(record + blkt_offset + 4);
693
694 if (swapflag)
695 {
696 ms_gswap4 (&blkt_200->amplitude);
697 ms_gswap4 (&blkt_200->period);
698 ms_gswap4 (&blkt_200->background_estimate);
699 MS_SWAPBTIME (&blkt_200->time);
700 }
701
702 if (details >= 1)
703 {
704 ms_log (0, " signal amplitude: %g\n", blkt_200->amplitude);
705 ms_log (0, " signal period: %g\n", blkt_200->period);
706 ms_log (0, " background estimate: %g\n", blkt_200->background_estimate);
707
708 if (details > 1)
709 {
710 b = blkt_200->flags;
711 ms_log (0, " event detection flags: [%u%u%u%u%u%u%u%u] 8 bits\n",
712 bit (b, 0x01), bit (b, 0x02), bit (b, 0x04), bit (b, 0x08),
713 bit (b, 0x10), bit (b, 0x20), bit (b, 0x40), bit (b, 0x80));
714 if (b & 0x01)
715 ms_log (0, " [Bit 0] 1: Dilatation wave\n");
716 else
717 ms_log (0, " [Bit 0] 0: Compression wave\n");
718 if (b & 0x02)
719 ms_log (0, " [Bit 1] 1: Units after deconvolution\n");
720 else
721 ms_log (0, " [Bit 1] 0: Units are digital counts\n");
722 if (b & 0x04)
723 ms_log (0, " [Bit 2] Bit 0 is undetermined\n");
724 ms_log (0, " reserved byte: %u\n", blkt_200->reserved);
725 }
726
727 ms_log (0, " signal onset time: %d,%d,%d:%d:%d.%04d (unused: %d)\n", blkt_200->time.year, blkt_200->time.day,
728 blkt_200->time.hour, blkt_200->time.min, blkt_200->time.sec, blkt_200->time.fract, blkt_200->time.unused);
729 ms_log (0, " detector name: %.24s\n", blkt_200->detector);
730 }
731 }
732
733 else if (blkt_type == 201)
734 {
735 struct blkt_201_s *blkt_201 = (struct blkt_201_s *)(record + blkt_offset + 4);
736
737 if (swapflag)
738 {
739 ms_gswap4 (&blkt_201->amplitude);
740 ms_gswap4 (&blkt_201->period);
741 ms_gswap4 (&blkt_201->background_estimate);
742 MS_SWAPBTIME (&blkt_201->time);
743 }
744
745 if (details >= 1)
746 {
747 ms_log (0, " signal amplitude: %g\n", blkt_201->amplitude);
748 ms_log (0, " signal period: %g\n", blkt_201->period);
749 ms_log (0, " background estimate: %g\n", blkt_201->background_estimate);
750
751 b = blkt_201->flags;
752 ms_log (0, " event detection flags: [%u%u%u%u%u%u%u%u] 8 bits\n",
753 bit (b, 0x01), bit (b, 0x02), bit (b, 0x04), bit (b, 0x08),
754 bit (b, 0x10), bit (b, 0x20), bit (b, 0x40), bit (b, 0x80));
755 if (b & 0x01)
756 ms_log (0, " [Bit 0] 1: Dilation wave\n");
757 else
758 ms_log (0, " [Bit 0] 0: Compression wave\n");
759
760 if (details > 1)
761 ms_log (0, " reserved byte: %u\n", blkt_201->reserved);
762 ms_log (0, " signal onset time: %d,%d,%d:%d:%d.%04d (unused: %d)\n", blkt_201->time.year, blkt_201->time.day,
763 blkt_201->time.hour, blkt_201->time.min, blkt_201->time.sec, blkt_201->time.fract, blkt_201->time.unused);
764 ms_log (0, " SNR values: ");
765 for (idx = 0; idx < 6; idx++)
766 ms_log (0, "%u ", blkt_201->snr_values[idx]);
767 ms_log (0, "\n");
768 ms_log (0, " loopback value: %u\n", blkt_201->loopback);
769 ms_log (0, " pick algorithm: %u\n", blkt_201->pick_algorithm);
770 ms_log (0, " detector name: %.24s\n", blkt_201->detector);
771 }
772 }
773
774 else if (blkt_type == 300)
775 {
776 struct blkt_300_s *blkt_300 = (struct blkt_300_s *)(record + blkt_offset + 4);
777
778 if (swapflag)
779 {
780 MS_SWAPBTIME (&blkt_300->time);
781 ms_gswap4 (&blkt_300->step_duration);
782 ms_gswap4 (&blkt_300->interval_duration);
783 ms_gswap4 (&blkt_300->amplitude);
784 ms_gswap4 (&blkt_300->reference_amplitude);
785 }
786
787 if (details >= 1)
788 {
789 ms_log (0, " calibration start time: %d,%d,%d:%d:%d.%04d (unused: %d)\n", blkt_300->time.year, blkt_300->time.day,
790 blkt_300->time.hour, blkt_300->time.min, blkt_300->time.sec, blkt_300->time.fract, blkt_300->time.unused);
791 ms_log (0, " number of calibrations: %u\n", blkt_300->numcalibrations);
792
793 b = blkt_300->flags;
794 ms_log (0, " calibration flags: [%u%u%u%u%u%u%u%u] 8 bits\n",
795 bit (b, 0x01), bit (b, 0x02), bit (b, 0x04), bit (b, 0x08),
796 bit (b, 0x10), bit (b, 0x20), bit (b, 0x40), bit (b, 0x80));
797 if (b & 0x01)
798 ms_log (0, " [Bit 0] First pulse is positive\n");
799 if (b & 0x02)
800 ms_log (0, " [Bit 1] Calibration's alternate sign\n");
801 if (b & 0x04)
802 ms_log (0, " [Bit 2] Calibration was automatic\n");
803 if (b & 0x08)
804 ms_log (0, " [Bit 3] Calibration continued from previous record(s)\n");
805
806 ms_log (0, " step duration: %u\n", blkt_300->step_duration);
807 ms_log (0, " interval duration: %u\n", blkt_300->interval_duration);
808 ms_log (0, " signal amplitude: %g\n", blkt_300->amplitude);
809 ms_log (0, " input signal channel: %.3s", blkt_300->input_channel);
810 if (details > 1)
811 ms_log (0, " reserved byte: %u\n", blkt_300->reserved);
812 ms_log (0, " reference amplitude: %u\n", blkt_300->reference_amplitude);
813 ms_log (0, " coupling: %.12s\n", blkt_300->coupling);
814 ms_log (0, " rolloff: %.12s\n", blkt_300->rolloff);
815 }
816 }
817
818 else if (blkt_type == 310)
819 {
820 struct blkt_310_s *blkt_310 = (struct blkt_310_s *)(record + blkt_offset + 4);
821
822 if (swapflag)
823 {
824 MS_SWAPBTIME (&blkt_310->time);
825 ms_gswap4 (&blkt_310->duration);
826 ms_gswap4 (&blkt_310->period);
827 ms_gswap4 (&blkt_310->amplitude);
828 ms_gswap4 (&blkt_310->reference_amplitude);
829 }
830
831 if (details >= 1)
832 {
833 ms_log (0, " calibration start time: %d,%d,%d:%d:%d.%04d (unused: %d)\n", blkt_310->time.year, blkt_310->time.day,
834 blkt_310->time.hour, blkt_310->time.min, blkt_310->time.sec, blkt_310->time.fract, blkt_310->time.unused);
835 if (details > 1)
836 ms_log (0, " reserved byte: %u\n", blkt_310->reserved1);
837
838 b = blkt_310->flags;
839 ms_log (0, " calibration flags: [%u%u%u%u%u%u%u%u] 8 bits\n",
840 bit (b, 0x01), bit (b, 0x02), bit (b, 0x04), bit (b, 0x08),
841 bit (b, 0x10), bit (b, 0x20), bit (b, 0x40), bit (b, 0x80));
842 if (b & 0x04)
843 ms_log (0, " [Bit 2] Calibration was automatic\n");
844 if (b & 0x08)
845 ms_log (0, " [Bit 3] Calibration continued from previous record(s)\n");
846 if (b & 0x10)
847 ms_log (0, " [Bit 4] Peak-to-peak amplitude\n");
848 if (b & 0x20)
849 ms_log (0, " [Bit 5] Zero-to-peak amplitude\n");
850 if (b & 0x40)
851 ms_log (0, " [Bit 6] RMS amplitude\n");
852
853 ms_log (0, " calibration duration: %u\n", blkt_310->duration);
854 ms_log (0, " signal period: %g\n", blkt_310->period);
855 ms_log (0, " signal amplitude: %g\n", blkt_310->amplitude);
856 ms_log (0, " input signal channel: %.3s", blkt_310->input_channel);
857 if (details > 1)
858 ms_log (0, " reserved byte: %u\n", blkt_310->reserved2);
859 ms_log (0, " reference amplitude: %u\n", blkt_310->reference_amplitude);
860 ms_log (0, " coupling: %.12s\n", blkt_310->coupling);
861 ms_log (0, " rolloff: %.12s\n", blkt_310->rolloff);
862 }
863 }
864
865 else if (blkt_type == 320)
866 {
867 struct blkt_320_s *blkt_320 = (struct blkt_320_s *)(record + blkt_offset + 4);
868
869 if (swapflag)
870 {
871 MS_SWAPBTIME (&blkt_320->time);
872 ms_gswap4 (&blkt_320->duration);
873 ms_gswap4 (&blkt_320->ptp_amplitude);
874 ms_gswap4 (&blkt_320->reference_amplitude);
875 }
876
877 if (details >= 1)
878 {
879 ms_log (0, " calibration start time: %d,%d,%d:%d:%d.%04d (unused: %d)\n", blkt_320->time.year, blkt_320->time.day,
880 blkt_320->time.hour, blkt_320->time.min, blkt_320->time.sec, blkt_320->time.fract, blkt_320->time.unused);
881 if (details > 1)
882 ms_log (0, " reserved byte: %u\n", blkt_320->reserved1);
883
884 b = blkt_320->flags;
885 ms_log (0, " calibration flags: [%u%u%u%u%u%u%u%u] 8 bits\n",
886 bit (b, 0x01), bit (b, 0x02), bit (b, 0x04), bit (b, 0x08),
887 bit (b, 0x10), bit (b, 0x20), bit (b, 0x40), bit (b, 0x80));
888 if (b & 0x04)
889 ms_log (0, " [Bit 2] Calibration was automatic\n");
890 if (b & 0x08)
891 ms_log (0, " [Bit 3] Calibration continued from previous record(s)\n");
892 if (b & 0x10)
893 ms_log (0, " [Bit 4] Random amplitudes\n");
894
895 ms_log (0, " calibration duration: %u\n", blkt_320->duration);
896 ms_log (0, " peak-to-peak amplitude: %g\n", blkt_320->ptp_amplitude);
897 ms_log (0, " input signal channel: %.3s", blkt_320->input_channel);
898 if (details > 1)
899 ms_log (0, " reserved byte: %u\n", blkt_320->reserved2);
900 ms_log (0, " reference amplitude: %u\n", blkt_320->reference_amplitude);
901 ms_log (0, " coupling: %.12s\n", blkt_320->coupling);
902 ms_log (0, " rolloff: %.12s\n", blkt_320->rolloff);
903 ms_log (0, " noise type: %.8s\n", blkt_320->noise_type);
904 }
905 }
906
907 else if (blkt_type == 390)
908 {
909 struct blkt_390_s *blkt_390 = (struct blkt_390_s *)(record + blkt_offset + 4);
910
911 if (swapflag)
912 {
913 MS_SWAPBTIME (&blkt_390->time);
914 ms_gswap4 (&blkt_390->duration);
915 ms_gswap4 (&blkt_390->amplitude);
916 }
917
918 if (details >= 1)
919 {
920 ms_log (0, " calibration start time: %d,%d,%d:%d:%d.%04d (unused: %d)\n", blkt_390->time.year, blkt_390->time.day,
921 blkt_390->time.hour, blkt_390->time.min, blkt_390->time.sec, blkt_390->time.fract, blkt_390->time.unused);
922 if (details > 1)
923 ms_log (0, " reserved byte: %u\n", blkt_390->reserved1);
924
925 b = blkt_390->flags;
926 ms_log (0, " calibration flags: [%u%u%u%u%u%u%u%u] 8 bits\n",
927 bit (b, 0x01), bit (b, 0x02), bit (b, 0x04), bit (b, 0x08),
928 bit (b, 0x10), bit (b, 0x20), bit (b, 0x40), bit (b, 0x80));
929 if (b & 0x04)
930 ms_log (0, " [Bit 2] Calibration was automatic\n");
931 if (b & 0x08)
932 ms_log (0, " [Bit 3] Calibration continued from previous record(s)\n");
933
934 ms_log (0, " calibration duration: %u\n", blkt_390->duration);
935 ms_log (0, " signal amplitude: %g\n", blkt_390->amplitude);
936 ms_log (0, " input signal channel: %.3s", blkt_390->input_channel);
937 if (details > 1)
938 ms_log (0, " reserved byte: %u\n", blkt_390->reserved2);
939 }
940 }
941
942 else if (blkt_type == 395)
943 {
944 struct blkt_395_s *blkt_395 = (struct blkt_395_s *)(record + blkt_offset + 4);
945
946 if (swapflag)
947 MS_SWAPBTIME (&blkt_395->time);
948
949 if (details >= 1)
950 {
951 ms_log (0, " calibration end time: %d,%d,%d:%d:%d.%04d (unused: %d)\n", blkt_395->time.year, blkt_395->time.day,
952 blkt_395->time.hour, blkt_395->time.min, blkt_395->time.sec, blkt_395->time.fract, blkt_395->time.unused);
953 if (details > 1)
954 ms_log (0, " reserved bytes (2): %u,%u\n",
955 blkt_395->reserved[0], blkt_395->reserved[1]);
956 }
957 }
958
959 else if (blkt_type == 400)
960 {
961 struct blkt_400_s *blkt_400 = (struct blkt_400_s *)(record + blkt_offset + 4);
962
963 if (swapflag)
964 {
965 ms_gswap4 (&blkt_400->azimuth);
966 ms_gswap4 (&blkt_400->slowness);
967 ms_gswap4 (&blkt_400->configuration);
968 }
969
970 if (details >= 1)
971 {
972 ms_log (0, " beam azimuth (degrees): %g\n", blkt_400->azimuth);
973 ms_log (0, " beam slowness (sec/degree): %g\n", blkt_400->slowness);
974 ms_log (0, " configuration: %u\n", blkt_400->configuration);
975 if (details > 1)
976 ms_log (0, " reserved bytes (2): %u,%u\n",
977 blkt_400->reserved[0], blkt_400->reserved[1]);
978 }
979 }
980
981 else if (blkt_type == 405)
982 {
983 struct blkt_405_s *blkt_405 = (struct blkt_405_s *)(record + blkt_offset + 4);
984 uint16_t firstvalue = blkt_405->delay_values[0]; /* Work on a private copy */
985
986 if (swapflag)
987 ms_gswap2 (&firstvalue);
988
989 if (details >= 1)
990 ms_log (0, " first delay value: %u\n", firstvalue);
991 }
992
993 else if (blkt_type == 500)
994 {
995 struct blkt_500_s *blkt_500 = (struct blkt_500_s *)(record + blkt_offset + 4);
996
997 if (swapflag)
998 {
999 ms_gswap4 (&blkt_500->vco_correction);
1000 MS_SWAPBTIME (&blkt_500->time);
1001 ms_gswap4 (&blkt_500->exception_count);
1002 }
1003
1004 if (details >= 1)
1005 {
1006 ms_log (0, " VCO correction: %g%%\n", blkt_500->vco_correction);
1007 ms_log (0, " time of exception: %d,%d,%d:%d:%d.%04d (unused: %d)\n", blkt_500->time.year, blkt_500->time.day,
1008 blkt_500->time.hour, blkt_500->time.min, blkt_500->time.sec, blkt_500->time.fract, blkt_500->time.unused);
1009 ms_log (0, " usec: %d\n", blkt_500->usec);
1010 ms_log (0, " reception quality: %u%%\n", blkt_500->reception_qual);
1011 ms_log (0, " exception count: %u\n", blkt_500->exception_count);
1012 ms_log (0, " exception type: %.16s\n", blkt_500->exception_type);
1013 ms_log (0, " clock model: %.32s\n", blkt_500->clock_model);
1014 ms_log (0, " clock status: %.128s\n", blkt_500->clock_status);
1015 }
1016 }
1017
1018 else if (blkt_type == 1000)
1019 {
1020 struct blkt_1000_s *blkt_1000 = (struct blkt_1000_s *)(record + blkt_offset + 4);
1021 char order[40];
1022
1023 /* Calculate record size in bytes as 2^(blkt_1000->rec_len) */
1024 b1000reclen = (unsigned int)1 << blkt_1000->reclen;
1025
1026 /* Big or little endian? */
1027 if (blkt_1000->byteorder == 0)
1028 strncpy (order, "Little endian", sizeof (order) - 1);
1029 else if (blkt_1000->byteorder == 1)
1030 strncpy (order, "Big endian", sizeof (order) - 1);
1031 else
1032 strncpy (order, "Unknown value", sizeof (order) - 1);
1033
1034 if (details >= 1)
1035 {
1036 ms_log (0, " encoding: %s (val:%u)\n",
1037 (char *)ms_encodingstr (blkt_1000->encoding), blkt_1000->encoding);
1038 ms_log (0, " byte order: %s (val:%u)\n",
1039 order, blkt_1000->byteorder);
1040 ms_log (0, " record length: %d (val:%u)\n",
1041 b1000reclen, blkt_1000->reclen);
1042
1043 if (details > 1)
1044 ms_log (0, " reserved byte: %u\n", blkt_1000->reserved);
1045 }
1046
1047 /* Save encoding format */
1048 b1000encoding = blkt_1000->encoding;
1049
1050 /* Sanity check encoding format */
1051 if (!(b1000encoding >= 0 && b1000encoding <= 5) &&
1052 !(b1000encoding >= 10 && b1000encoding <= 19) &&
1053 !(b1000encoding >= 30 && b1000encoding <= 33))
1054 {
1055 ms_log (2, "%s: Blockette 1000 encoding format invalid (0-5,10-19,30-33): %d\n", srcname, b1000encoding);
1056 retval++;
1057 }
1058
1059 /* Sanity check byte order flag */
1060 if (blkt_1000->byteorder != 0 && blkt_1000->byteorder != 1)
1061 {
1062 ms_log (2, "%s: Blockette 1000 byte order flag invalid (0 or 1): %d\n", srcname, blkt_1000->byteorder);
1063 retval++;
1064 }
1065 }
1066
1067 else if (blkt_type == 1001)
1068 {
1069 struct blkt_1001_s *blkt_1001 = (struct blkt_1001_s *)(record + blkt_offset + 4);
1070
1071 if (details >= 1)
1072 {
1073 ms_log (0, " timing quality: %u%%\n", blkt_1001->timing_qual);
1074 ms_log (0, " micro second: %d\n", blkt_1001->usec);
1075
1076 if (details > 1)
1077 ms_log (0, " reserved byte: %u\n", blkt_1001->reserved);
1078
1079 ms_log (0, " frame count: %u\n", blkt_1001->framecnt);
1080 }
1081 }
1082
1083 else if (blkt_type == 2000)
1084 {
1085 struct blkt_2000_s *blkt_2000 = (struct blkt_2000_s *)(record + blkt_offset + 4);
1086 char order[40];
1087
1088 if (swapflag)
1089 {
1090 ms_gswap2 (&blkt_2000->length);
1091 ms_gswap2 (&blkt_2000->data_offset);
1092 ms_gswap4 (&blkt_2000->recnum);
1093 }
1094
1095 /* Big or little endian? */
1096 if (blkt_2000->byteorder == 0)
1097 strncpy (order, "Little endian", sizeof (order) - 1);
1098 else if (blkt_2000->byteorder == 1)
1099 strncpy (order, "Big endian", sizeof (order) - 1);
1100 else
1101 strncpy (order, "Unknown value", sizeof (order) - 1);
1102
1103 if (details >= 1)
1104 {
1105 ms_log (0, " blockette length: %u\n", blkt_2000->length);
1106 ms_log (0, " data offset: %u\n", blkt_2000->data_offset);
1107 ms_log (0, " record number: %u\n", blkt_2000->recnum);
1108 ms_log (0, " byte order: %s (val:%u)\n",
1109 order, blkt_2000->byteorder);
1110 b = blkt_2000->flags;
1111 ms_log (0, " data flags: [%u%u%u%u%u%u%u%u] 8 bits\n",
1112 bit (b, 0x01), bit (b, 0x02), bit (b, 0x04), bit (b, 0x08),
1113 bit (b, 0x10), bit (b, 0x20), bit (b, 0x40), bit (b, 0x80));
1114
1115 if (details > 1)
1116 {
1117 if (b & 0x01)
1118 ms_log (0, " [Bit 0] 1: Stream oriented\n");
1119 else
1120 ms_log (0, " [Bit 0] 0: Record oriented\n");
1121 if (b & 0x02)
1122 ms_log (0, " [Bit 1] 1: Blockette 2000s may NOT be packaged\n");
1123 else
1124 ms_log (0, " [Bit 1] 0: Blockette 2000s may be packaged\n");
1125 if (!(b & 0x04) && !(b & 0x08))
1126 ms_log (0, " [Bits 2-3] 00: Complete blockette\n");
1127 else if (!(b & 0x04) && (b & 0x08))
1128 ms_log (0, " [Bits 2-3] 01: First blockette in span\n");
1129 else if ((b & 0x04) && (b & 0x08))
1130 ms_log (0, " [Bits 2-3] 11: Continuation blockette in span\n");
1131 else if ((b & 0x04) && !(b & 0x08))
1132 ms_log (0, " [Bits 2-3] 10: Final blockette in span\n");
1133 if (!(b & 0x10) && !(b & 0x20))
1134 ms_log (0, " [Bits 4-5] 00: Not file oriented\n");
1135 else if (!(b & 0x10) && (b & 0x20))
1136 ms_log (0, " [Bits 4-5] 01: First blockette of file\n");
1137 else if ((b & 0x10) && !(b & 0x20))
1138 ms_log (0, " [Bits 4-5] 10: Continuation of file\n");
1139 else if ((b & 0x10) && (b & 0x20))
1140 ms_log (0, " [Bits 4-5] 11: Last blockette of file\n");
1141 }
1142
1143 ms_log (0, " number of headers: %u\n", blkt_2000->numheaders);
1144
1145 /* Crude display of the opaque data headers */
1146 if (details > 1)
1147 ms_log (0, " headers: %.*s\n",
1148 (blkt_2000->data_offset - 15), blkt_2000->payload);
1149 }
1150 }
1151
1152 else
1153 {
1154 ms_log (2, "%s: Unrecognized blockette type: %d\n", srcname, blkt_type);
1155 retval++;
1156 }
1157
1158 /* Sanity check the next blockette offset */
1159 if (next_blkt && next_blkt <= endofblockettes)
1160 {
1161 ms_log (2, "%s: Next blockette offset (%d) is within current blockette ending at byte %d\n",
1162 srcname, next_blkt, endofblockettes);
1163 blkt_offset = 0;
1164 }
1165 else
1166 {
1167 blkt_offset = next_blkt;
1168 }
1169
1170 blkt_count++;
1171 } /* End of looping through blockettes */
1172
1173 /* Check that the blockette offset is within the maximum record size */
1174 if (blkt_offset > maxreclen)
1175 {
1176 ms_log (2, "%s: Blockette offset (%d) beyond maximum record length (%d)\n", srcname, blkt_offset, maxreclen);
1177 retval++;
1178 }
1179
1180 /* Check that the data and blockette offsets are within the record */
1181 if (b1000reclen && fsdh->data_offset > b1000reclen)
1182 {
1183 ms_log (2, "%s: Data offset (%d) beyond record length (%d)\n", srcname, fsdh->data_offset, b1000reclen);
1184 retval++;
1185 }
1186 if (b1000reclen && fsdh->blockette_offset > b1000reclen)
1187 {
1188 ms_log (2, "%s: Blockette offset (%d) beyond record length (%d)\n", srcname, fsdh->blockette_offset, b1000reclen);
1189 retval++;
1190 }
1191
1192 /* Check that the data offset is beyond the end of the blockettes */
1193 if (fsdh->numsamples && fsdh->data_offset <= endofblockettes)
1194 {
1195 ms_log (2, "%s: Data offset (%d) is within blockette chain (end of blockettes: %d)\n", srcname, fsdh->data_offset, endofblockettes);
1196 retval++;
1197 }
1198
1199 /* Check that the correct number of blockettes were parsed */
1200 if (fsdh->numblockettes != blkt_count)
1201 {
1202 ms_log (2, "%s: Specified number of blockettes (%d) not equal to those parsed (%d)\n", srcname, fsdh->numblockettes, blkt_count);
1203 retval++;
1204 }
1205 }
1206
1207 return retval;
1208 } /* End of ms_parse_raw() */
1209