Coverity fix.
[u/mrichter/AliRoot.git] / RAW / AliRawReader.cxx
1 /**************************************************************************
2  * Copyright(c) 1998-1999, ALICE Experiment at CERN, All rights reserved. *
3  *                                                                        *
4  * Author: The ALICE Off-line Project.                                    *
5  * Contributors are mentioned in the code where appropriate.              *
6  *                                                                        *
7  * Permission to use, copy, modify and distribute this software and its   *
8  * documentation strictly for non-commercial purposes is hereby granted   *
9  * without fee, provided that the above copyright notice appears in all   *
10  * copies and that both the copyright notice and this permission notice   *
11  * appear in the supporting documentation. The authors make no claims     *
12  * about the suitability of this software for any purpose. It is          *
13  * provided "as is" without express or implied warranty.                  *
14  **************************************************************************/
15
16 /* $Id$ */
17
18 ///////////////////////////////////////////////////////////////////////////////
19 ///
20 /// This is the base class for reading raw data.
21 ///
22 /// The derived classes, which operate on concrete raw data formats,
23 /// should implement
24 /// - ReadHeader to read the next (data/equipment) header
25 /// - ReadNextData to read the next raw data block (=1 DDL)
26 /// - ReadNext to read a given number of bytes
27 /// - several getters like GetType
28 ///
29 /// Sequential access to the raw data is provided by the methods
30 /// ReadHeader, ReadNextData, ReadNextInt, ReadNextShort, ReadNextChar
31 ///
32 /// If only data from a specific detector (and a given range of DDL numbers)
33 /// should be read, this can be achieved by the Select method.
34 /// Several getters provide information about the current event and the
35 /// current type of raw data.
36 ///
37 ///////////////////////////////////////////////////////////////////////////////
38
39 #include <TClass.h>
40 #include <TPluginManager.h>
41 #include <TROOT.h>
42 #include <TInterpreter.h>
43 #include <TSystem.h>
44
45 #include <Riostream.h>
46 #include "AliRawReader.h"
47 #include "AliRawReaderFile.h"
48 #include "AliRawReaderDate.h"
49 #include "AliRawReaderRoot.h"
50 #include "AliRawReaderChain.h"
51 #include "AliDAQ.h"
52 #include "AliLog.h"
53
54 ClassImp(AliRawReader)
55
56
57 AliRawReader::AliRawReader() :
58   fEquipmentIdsIn(NULL),
59   fEquipmentIdsOut(NULL),
60   fRequireHeader(kTRUE),
61   fHeader(NULL),
62   fCount(0),
63   fSelectEquipmentType(-1),
64   fSelectMinEquipmentId(-1),
65   fSelectMaxEquipmentId(-1),
66   fSkipInvalid(kFALSE),
67   fSelectEventType(-1),
68   fSelectTriggerMask(0),
69   fSelectTriggerExpr(),
70   fErrorCode(0),
71   fEventNumber(-1),
72   fErrorLogs("AliRawDataErrorLog",100),
73   fHeaderSwapped(NULL),
74   fIsValid(kTRUE)
75 {
76 // default constructor: initialize data members
77 // Allocate the swapped header in case of Mac
78 #ifndef R__BYTESWAP
79   fHeaderSwapped=new AliRawDataHeader();
80 #endif
81 }
82
83 Bool_t AliRawReader::LoadEquipmentIdsMap(const char *fileName)
84 {
85   // Open the mapping file
86   // and load the mapping data
87   ifstream input(fileName);
88   if (input.is_open()) {
89     Warning("AliRawReader","Equipment ID mapping file is found !");
90     const Int_t kMaxDDL = 256;
91     fEquipmentIdsIn = new TArrayI(kMaxDDL);
92     fEquipmentIdsOut = new TArrayI(kMaxDDL);
93     Int_t equipIn, equipOut;
94     Int_t nIds = 0;
95     while (input >> equipIn >> equipOut) {
96       if (nIds >= kMaxDDL) {
97         Error("AliRawReader","Too many equipment Id mappings found ! Truncating the list !");
98         break;
99       }
100       fEquipmentIdsIn->AddAt(equipIn,nIds); 
101       fEquipmentIdsOut->AddAt(equipOut,nIds);
102       nIds++;
103     }
104     fEquipmentIdsIn->Set(nIds);
105     fEquipmentIdsOut->Set(nIds);
106     input.close();
107     return kTRUE;
108   }
109   else {
110     Error("AliRawReader","equipment id map file is not found ! Skipping the mapping !");
111     return kFALSE;
112   }
113 }
114
115 AliRawReader::AliRawReader(const AliRawReader& rawReader) :
116   TObject(rawReader),
117   fEquipmentIdsIn(rawReader.fEquipmentIdsIn),
118   fEquipmentIdsOut(rawReader.fEquipmentIdsOut),
119   fRequireHeader(rawReader.fRequireHeader),
120   fHeader(rawReader.fHeader),
121   fCount(rawReader.fCount),
122   fSelectEquipmentType(rawReader.fSelectEquipmentType),
123   fSelectMinEquipmentId(rawReader.fSelectMinEquipmentId),
124   fSelectMaxEquipmentId(rawReader.fSelectMaxEquipmentId),
125   fSkipInvalid(rawReader.fSkipInvalid),
126   fSelectEventType(rawReader.fSelectEventType),
127   fSelectTriggerMask(rawReader.fSelectTriggerMask),
128   fSelectTriggerExpr(rawReader.fSelectTriggerExpr),
129   fErrorCode(0),
130   fEventNumber(-1),
131   fErrorLogs("AliRawDataErrorLog",100),
132   fHeaderSwapped(NULL),
133   fIsValid(rawReader.fIsValid)
134 {
135 // copy constructor
136 // Allocate the swapped header in case of Mac
137 #ifndef R__BYTESWAP
138   fHeaderSwapped=new AliRawDataHeader(*rawReader.fHeaderSwapped);
139 #endif
140 }
141
142 AliRawReader& AliRawReader::operator = (const AliRawReader& rawReader)
143 {
144 // assignment operator
145   fEquipmentIdsIn = rawReader.fEquipmentIdsIn;
146   fEquipmentIdsOut = rawReader.fEquipmentIdsOut;
147
148   fHeader = rawReader.fHeader;
149   fCount = rawReader.fCount;
150
151   fSelectEquipmentType = rawReader.fSelectEquipmentType;
152   fSelectMinEquipmentId = rawReader.fSelectMinEquipmentId;
153   fSelectMaxEquipmentId = rawReader.fSelectMaxEquipmentId;
154   fSkipInvalid = rawReader.fSkipInvalid;
155   fSelectEventType = rawReader.fSelectEventType;
156   fSelectTriggerMask = rawReader.fSelectTriggerMask;
157   fSelectTriggerExpr = rawReader.fSelectTriggerExpr;
158
159   fErrorCode = rawReader.fErrorCode;
160
161   fEventNumber = rawReader.fEventNumber;
162   fErrorLogs = *((TClonesArray*)rawReader.fErrorLogs.Clone());
163
164   fIsValid = rawReader.fIsValid;
165
166   return *this;
167 }
168
169 AliRawReader::~AliRawReader()
170 {
171   // destructor
172   // delete the mapping arrays if
173   // initialized
174   if (fEquipmentIdsIn) delete fEquipmentIdsIn;
175   if (fEquipmentIdsOut) delete fEquipmentIdsOut;
176   fErrorLogs.Delete();
177   if (fHeaderSwapped) delete fHeaderSwapped;
178 }
179
180 AliRawReader* AliRawReader::Create(const char *uri)
181 {
182   // RawReader's factory
183   // It instantiate corresponding raw-reader implementation class object
184   // depending on the URI provided
185   // Normal URIs point to files, while the URI starting with
186   // 'mem://:' or 'mem://<filename>' will create
187   // AliRawReaderDateOnline object which is supposed to be used
188   // in the online reconstruction
189
190   TString strURI = uri;
191
192   if (strURI.IsNull()) {
193     AliWarningClass("No raw-reader created");
194     return NULL;
195   }
196
197   TObjArray *fields = strURI.Tokenize("?");
198   TString &fileURI = ((TObjString*)fields->At(0))->String();
199
200   AliRawReader *rawReader = NULL;
201   if (fileURI.BeginsWith("mem://") || fileURI.BeginsWith("^")) {
202     if (fileURI.BeginsWith("mem://")) fileURI.ReplaceAll("mem://","");
203     AliInfoClass(Form("Creating raw-reader in order to read events in shared memory (option=%s)",fileURI.Data()));
204
205     TPluginManager* pluginManager = gROOT->GetPluginManager();
206     TString rawReaderName = "AliRawReaderDateOnline";
207     TPluginHandler* pluginHandler = pluginManager->FindHandler("AliRawReader", "online");
208     // if not, add a plugin for it
209     if (!pluginHandler) {
210       pluginManager->AddHandler("AliRawReader", "online", 
211                                 "AliRawReaderDateOnline", "RAWDatarecOnline", "AliRawReaderDateOnline(const char*)");
212       pluginHandler = pluginManager->FindHandler("AliRawReader", "online");
213     }
214     if (pluginHandler && (pluginHandler->LoadPlugin() == 0)) {
215       rawReader = (AliRawReader*)pluginHandler->ExecPlugin(1,fileURI.Data());
216     }
217     else {
218       delete fields;
219       return NULL;
220     }
221   }
222   else if (fileURI.BeginsWith("amore://")) {
223     // A special raw-data URL used in case
224     // the raw-data reading is steered from
225     // ouside, i.e. from AMORE
226     fileURI.ReplaceAll("amore://","");
227     AliInfoClass("Creating raw-reader in order to read events sent by AMORE");
228     rawReader = new AliRawReaderDate((void *)NULL);
229   }
230   else if (fileURI.BeginsWith("collection://")) {
231     fileURI.ReplaceAll("collection://","");
232     AliInfoClass(Form("Creating raw-reader in order to read raw-data files collection defined in %s",fileURI.Data()));
233     rawReader = new AliRawReaderChain(fileURI);
234   }
235   else if (fileURI.BeginsWith("raw://run")) {
236     fileURI.ReplaceAll("raw://run","");
237     if (fileURI.IsDigit()) {
238       rawReader = new AliRawReaderChain(fileURI.Atoi());
239     }
240     else {
241       AliErrorClass(Form("Invalid syntax: %s",fileURI.Data()));
242       fields->Delete();
243       return NULL;
244     }
245   }
246   else {
247     AliInfoClass(Form("Creating raw-reader in order to read raw-data file: %s",fileURI.Data()));
248     TString filename(gSystem->ExpandPathName(fileURI.Data()));
249     if (filename.EndsWith("/")) {
250       rawReader = new AliRawReaderFile(filename);
251     } else if (filename.EndsWith(".root")) {
252       rawReader = new AliRawReaderRoot(filename);
253     } else {
254       rawReader = new AliRawReaderDate(filename);
255     }
256   }
257
258   if (!rawReader->IsRawReaderValid()) {
259     AliErrorClass(Form("Raw-reader is invalid - check the input URI (%s)",fileURI.Data()));
260     delete rawReader;
261     fields->Delete();
262     delete fields;
263     return NULL;
264   }
265
266   // Now apply event selection criteria (if specified)
267   if (fields->GetEntries() > 1) {
268     Int_t eventType = -1;
269     ULong64_t triggerMask = 0;
270     TString triggerExpr;
271     for(Int_t i = 1; i < fields->GetEntries(); i++) {
272       if (!fields->At(i)) continue;
273       TString &option = ((TObjString*)fields->At(i))->String();
274       if (option.BeginsWith("EventType=",TString::kIgnoreCase)) {
275         option.ReplaceAll("EventType=","");
276         eventType = option.Atoi();
277         continue;
278       }
279       if (option.BeginsWith("Trigger=",TString::kIgnoreCase)) {
280         option.ReplaceAll("Trigger=","");
281         if (option.IsDigit()) {
282           triggerMask = option.Atoll();
283         }
284         else {
285           triggerExpr = option.Data();
286         }
287         continue;
288       }
289       AliWarningClass(Form("Ignoring invalid event selection option: %s",option.Data()));
290     }
291     AliInfoClass(Form("Event selection criteria specified:   eventype=%d   trigger mask=%llx   trigger expression=%s",
292                  eventType,triggerMask,triggerExpr.Data()));
293     rawReader->SelectEvents(eventType,triggerMask,triggerExpr.Data());
294   }
295
296   fields->Delete();
297   delete fields;
298
299   return rawReader;
300 }
301
302 Int_t AliRawReader::GetMappedEquipmentId() const
303 {
304   if (!fEquipmentIdsIn || !fEquipmentIdsOut) {
305     Error("AliRawReader","equipment Ids mapping is not initialized !");
306     return GetEquipmentId();
307   }
308   Int_t equipmentId = GetEquipmentId();
309   for(Int_t iId = 0; iId < fEquipmentIdsIn->GetSize(); iId++) {
310     if (equipmentId == fEquipmentIdsIn->At(iId)) {
311       equipmentId = fEquipmentIdsOut->At(iId);
312       break;
313     }
314   }
315   return equipmentId;
316 }
317
318 Int_t AliRawReader::GetDetectorID() const
319 {
320   // Get the detector ID
321   // The list of detector IDs
322   // can be found in AliDAQ.h
323   Int_t equipmentId;
324   if (fEquipmentIdsIn && fEquipmentIdsIn)
325     equipmentId = GetMappedEquipmentId();
326   else
327     equipmentId = GetEquipmentId();
328
329   if (equipmentId >= 0) {
330     Int_t ddlIndex;
331     return AliDAQ::DetectorIDFromDdlID(equipmentId,ddlIndex);
332   }
333   else
334     return -1;
335 }
336
337 Int_t AliRawReader::GetDDLID() const
338 {
339   // Get the DDL ID (within one sub-detector)
340   // The list of detector IDs
341   // can be found in AliDAQ.h
342   Int_t equipmentId;
343   if (fEquipmentIdsIn && fEquipmentIdsIn)
344     equipmentId = GetMappedEquipmentId();
345   else
346     equipmentId = GetEquipmentId();
347
348   if (equipmentId >= 0) {
349     Int_t ddlIndex;
350     AliDAQ::DetectorIDFromDdlID(equipmentId,ddlIndex);
351     return ddlIndex;
352   }
353   else
354     return -1;
355 }
356
357 void AliRawReader::Select(const char *detectorName, Int_t minDDLID, Int_t maxDDLID)
358 {
359 // read only data of the detector with the given name and in the given
360 // range of DDLs (minDDLID <= DDLID <= maxDDLID).
361 // no selection is applied if a value < 0 is used.
362   Int_t detectorID = AliDAQ::DetectorID(detectorName);
363   if(detectorID >= 0)
364     Select(detectorID,minDDLID,maxDDLID);
365 }
366
367 void AliRawReader::Select(Int_t detectorID, Int_t minDDLID, Int_t maxDDLID)
368 {
369 // read only data of the detector with the given ID and in the given
370 // range of DDLs (minDDLID <= DDLID <= maxDDLID).
371 // no selection is applied if a value < 0 is used.
372
373   fSelectEquipmentType = -1;
374
375   if (minDDLID < 0)
376     fSelectMinEquipmentId = AliDAQ::DdlIDOffset(detectorID);
377   else
378     fSelectMinEquipmentId = AliDAQ::DdlID(detectorID,minDDLID);
379
380   if (maxDDLID < 0)
381     fSelectMaxEquipmentId = AliDAQ::DdlID(detectorID,AliDAQ::NumberOfDdls(detectorID)-1);
382   else
383     fSelectMaxEquipmentId = AliDAQ::DdlID(detectorID,maxDDLID);
384 }
385
386 void AliRawReader::SelectEquipment(Int_t equipmentType, 
387                                    Int_t minEquipmentId, Int_t maxEquipmentId)
388 {
389 // read only data of the equipment with the given type and in the given
390 // range of IDs (minEquipmentId <= EquipmentId <= maxEquipmentId).
391 // no selection is applied if a value < 0 is used.
392
393   fSelectEquipmentType = equipmentType;
394   fSelectMinEquipmentId = minEquipmentId;
395   fSelectMaxEquipmentId = maxEquipmentId;
396 }
397
398 void AliRawReader::SelectEvents(Int_t type, ULong64_t triggerMask,
399                                 const char *triggerExpr)
400 {
401 // read only events with the given type and optionally
402 // trigger mask.
403 // no selection is applied if value = 0 is used.
404 // Trigger selection can be done via string (triggerExpr)
405 // which defines the trigger logic to be used. It works only
406 // after LoadTriggerClass() method is called for all involved
407 // trigger classes.
408
409   fSelectEventType = type;
410   fSelectTriggerMask = triggerMask;
411   if (triggerExpr) fSelectTriggerExpr = triggerExpr;
412 }
413
414 void AliRawReader::LoadTriggerClass(const char* name, Int_t index)
415 {
416   // Loads the list of trigger classes defined.
417   // Used in conjunction with IsEventSelected in the
418   // case when the trigger selection is given by
419   // fSelectedTriggerExpr
420
421   if (fSelectTriggerExpr.IsNull()) return;
422
423   fSelectTriggerExpr.ReplaceAll(name,Form("[%d]",index));
424 }
425
426 Bool_t AliRawReader::IsSelected() const
427 {
428 // apply the selection (if any)
429
430   if (fSkipInvalid && !IsValid()) return kFALSE;
431
432   if (fSelectEquipmentType >= 0)
433     if (GetEquipmentType() != fSelectEquipmentType) return kFALSE;
434
435   Int_t equipmentId;
436   if (fEquipmentIdsIn && fEquipmentIdsIn)
437     equipmentId = GetMappedEquipmentId();
438   else
439     equipmentId = GetEquipmentId();
440
441   if ((fSelectMinEquipmentId >= 0) && 
442       (equipmentId < fSelectMinEquipmentId))
443     return kFALSE;
444   if ((fSelectMaxEquipmentId >= 0) && 
445       (equipmentId > fSelectMaxEquipmentId))
446     return kFALSE;
447
448   return kTRUE;
449 }
450
451 Bool_t AliRawReader::IsEventSelected() const
452 {
453   // apply the event selection (if any)
454
455   // First check the event type
456   if (fSelectEventType >= 0) {
457     if (GetType() != (UInt_t) fSelectEventType) return kFALSE;
458   }
459
460   // Then check the trigger pattern and compared it
461   // to the required trigger mask
462   if (fSelectTriggerMask != 0) {
463     if ((GetClassMask() & fSelectTriggerMask) != fSelectTriggerMask) return kFALSE;
464   }
465
466   if (!fSelectTriggerExpr.IsNull()) {
467     TString expr(fSelectTriggerExpr);
468     ULong64_t mask = GetClassMask();
469     for(Int_t itrigger = 0; itrigger < 50; itrigger++) {
470       if (mask & (1 << itrigger)) {
471         expr.ReplaceAll(Form("[%d]",itrigger),"1");
472       }
473       else {
474         expr.ReplaceAll(Form("[%d]",itrigger),"0");
475       }
476     }
477     // Possibility to introduce downscaling
478     expr.ReplaceAll("%",Form("&& !%d %%",GetEventIndex()));
479     Int_t error;
480     if ((gROOT->ProcessLineFast(expr.Data(),&error) == 0) &&
481         (error == TInterpreter::kNoError)) {
482       return kFALSE;
483     }
484   }
485
486   return kTRUE;
487 }
488
489 UInt_t AliRawReader::SwapWord(UInt_t x) const
490 {
491    // Swap the endianess of the integer value 'x'
492
493    return (((x & 0x000000ffU) << 24) | ((x & 0x0000ff00U) <<  8) |
494            ((x & 0x00ff0000U) >>  8) | ((x & 0xff000000U) >> 24));
495 }
496
497 UShort_t AliRawReader::SwapShort(UShort_t x) const
498 {
499    // Swap the endianess of the short value 'x'
500
501    return (((x & 0x00ffU) <<  8) | ((x & 0xff00U) >>  8)) ;
502 }
503
504 Bool_t AliRawReader::ReadNextInt(UInt_t& data)
505 {
506 // reads the next 4 bytes at the current position
507 // returns kFALSE if the data could not be read
508
509   while (fCount == 0) {
510     if (!ReadHeader()) return kFALSE;
511   }
512   if (fCount < (Int_t) sizeof(data)) {
513     Error("ReadNextInt", 
514           "too few data left (%d bytes) to read an UInt_t!", fCount);
515     return kFALSE;
516   }
517   if (!ReadNext((UChar_t*) &data, sizeof(data))) {
518     Error("ReadNextInt", "could not read data!");
519     return kFALSE;
520   }
521 #ifndef R__BYTESWAP
522   data=SwapWord(data);
523 #endif
524   return kTRUE;
525 }
526
527 Bool_t AliRawReader::ReadNextShort(UShort_t& data)
528 {
529 // reads the next 2 bytes at the current position
530 // returns kFALSE if the data could not be read
531
532   while (fCount == 0) {
533     if (!ReadHeader()) return kFALSE;
534   }
535   if (fCount < (Int_t) sizeof(data)) {
536     Error("ReadNextShort", 
537           "too few data left (%d bytes) to read an UShort_t!", fCount);
538     return kFALSE;
539   }
540   if (!ReadNext((UChar_t*) &data, sizeof(data))) {
541     Error("ReadNextShort", "could not read data!");
542     return kFALSE;
543   }
544 #ifndef R__BYTESWAP
545   data=SwapShort(data);
546 #endif
547   return kTRUE;
548 }
549
550 Bool_t AliRawReader::ReadNextChar(UChar_t& data)
551 {
552 // reads the next 1 byte at the current stream position
553 // returns kFALSE if the data could not be read
554
555   while (fCount == 0) {
556     if (!ReadHeader()) return kFALSE;
557   }
558   if (!ReadNext((UChar_t*) &data, sizeof(data))) {
559     Error("ReadNextChar", "could not read data!");
560     return kFALSE;
561   }
562   return kTRUE;
563 }
564
565 Bool_t  AliRawReader::GotoEvent(Int_t event)
566 {
567   // Random access to certain
568   // event index. Could be very slow
569   // for some non-root raw-readers.
570   // So it should be reimplemented there.
571   if (event < fEventNumber) RewindEvents();
572
573   while (fEventNumber < event) {
574     if (!NextEvent()) return kFALSE;
575   }
576
577   return kTRUE;
578 }
579
580 Int_t AliRawReader::CheckData() const
581 {
582 // check the consistency of the data
583 // derived classes should overwrite the default method which returns 0 (no err)
584
585   return 0;
586 }
587
588
589 void AliRawReader::DumpData(Int_t limit)
590 {
591 // print the raw data
592 // if limit is not negative, only the first and last "limit" lines of raw data
593 // are printed
594
595   Reset();
596   if (!ReadHeader()) {
597     Error("DumpData", "no header");
598     return;
599   }
600   printf("header:\n"
601          " type = %d  run = %d  ", GetType(), GetRunNumber());
602   if (GetEventId()) {
603     printf("event = %8.8x %8.8x\n", GetEventId()[1], GetEventId()[0]);
604   } else {
605     printf("event = -------- --------\n");
606   }
607   if (GetTriggerPattern()) {
608     printf(" trigger = %8.8x %8.8x  ",
609            GetTriggerPattern()[1], GetTriggerPattern()[0]);
610   } else {
611     printf(" trigger = -------- --------  ");
612   }
613   if (GetDetectorPattern()) {
614     printf("detector = %8.8x\n", GetDetectorPattern()[0]);
615   } else {
616     printf("detector = --------\n");
617   }
618   if (GetAttributes()) {
619     printf(" attributes = %8.8x %8.8x %8.8x  ",
620            GetAttributes()[2], GetAttributes()[1], GetAttributes()[0]);
621   } else {
622     printf(" attributes = -------- -------- --------  ");
623   }
624   printf("GDC = %d\n", GetGDCId());
625   printf("\n");
626
627   do {
628     printf("-------------------------------------------------------------------------------\n");
629     printf("LDC = %d\n", GetLDCId());
630
631     printf("equipment:\n"
632            " size = %d  type = %d  id = %d\n",
633            GetEquipmentSize(), GetEquipmentType(), GetEquipmentId());
634     if (GetEquipmentAttributes()) {
635       printf(" attributes = %8.8x %8.8x %8.8x  ", GetEquipmentAttributes()[2],
636              GetEquipmentAttributes()[1], GetEquipmentAttributes()[0]);
637     } else {
638       printf(" attributes = -------- -------- --------  ");
639     }
640     printf("element size = %d\n", GetEquipmentElementSize());
641
642     printf("data header:\n"
643            " size = %d  version = %d  valid = %d  compression = %d\n",
644            GetDataSize(), GetVersion(), IsValid(), IsCompressed());
645
646     printf("\n");
647     if (limit == 0) continue;
648
649     Int_t size = GetDataSize();
650     char line[70];
651     for (Int_t i = 0; i < 70; i++) line[i] = ' ';
652     line[69] = '\0';
653     Int_t pos = 0;
654     Int_t max = 16;
655     UChar_t byte;
656
657     for (Int_t n = 0; n < size; n++) {
658       if (!ReadNextChar(byte)) {
659         Error("DumpData", "couldn't read byte number %d\n", n);
660         break;
661       }
662       if (pos >= max) {
663         printf("%8.8x  %s\n", n-pos, line);
664         for (Int_t i = 0; i < 70; i++) line[i] = ' ';
665         line[69] = '\0';
666         pos = 0;
667         if ((limit > 0) && (n/max == limit)) {
668           Int_t nContinue = ((size-1)/max+1-limit) * max;
669           if (nContinue > n) {
670             printf(" [skipping %d bytes]\n", nContinue-n);
671             n = nContinue-1;
672             continue;
673           }
674         }
675       }
676       Int_t offset = pos/4;
677       if ((byte > 0x20) && (byte < 0x7f)) {
678         line[pos+offset] = byte;
679       } else {
680         line[pos+offset] = '.';
681       }
682       char hex[3];
683       snprintf(hex, 3, "%2.2x", byte);
684       line[max+max/4+3+2*pos+offset] = hex[0];
685       line[max+max/4+4+2*pos+offset] = hex[1];
686       pos++;
687     }
688
689     if (pos > 0) printf("%8.8x  %s\n", size-pos, line);
690     printf("\n");
691            
692   } while (ReadHeader());
693 }
694
695 void AliRawReader::AddErrorLog(AliRawDataErrorLog::ERawDataErrorLevel level,
696                                Int_t code,
697                                const char *message)
698 {
699   // Add a raw data error message to the list
700   // of raw-data decoding errors
701   if (fEventNumber < 0) {
702     return;
703   }
704   Int_t ddlId = GetEquipmentId();
705   if (ddlId < 0) {
706     AliError("No ddl raw data have been read so far! Impossible to add a raw data error log!");
707     return;
708   }
709
710   Int_t prevEventNumber = -1;
711   Int_t prevDdlId = -1;
712   Int_t prevErrorCode = -1;
713   AliRawDataErrorLog *prevLog = (AliRawDataErrorLog *)fErrorLogs.Last();
714   if (prevLog) {
715     prevEventNumber = prevLog->GetEventNumber();
716     prevDdlId       = prevLog->GetDdlID();
717     prevErrorCode   = prevLog->GetErrorCode();
718   }
719
720   if ((prevEventNumber != fEventNumber) ||
721       (prevDdlId != ddlId) ||
722       (prevErrorCode != code)) {
723     new (fErrorLogs[fErrorLogs.GetEntriesFast()])
724       AliRawDataErrorLog(fEventNumber,
725                          ddlId,
726                          level,
727                          code,
728                          message);
729   }
730   else
731     if (prevLog) prevLog->AddCount();
732
733 }
734
735 Bool_t AliRawReader::GotoEventWithID(Int_t event, 
736                                      UInt_t period,
737                                      UInt_t orbitID,
738                                      UShort_t bcID)
739 {
740   // Go to certain event number by
741   // checking the event ID.
742   // Useful in case event-selection
743   // is applied and the 'event' is
744   // relative
745   if (!GotoEvent(event)) return kFALSE;
746
747   while (GetBCID()    != period  ||
748          GetOrbitID() != orbitID ||
749          GetPeriod()  != bcID) {
750     if (!NextEvent()) return kFALSE;
751   }
752
753   return kTRUE;
754 }
755