ReadFile.m

Go to the documentation of this file.
00001 /*
00002  *  ReadFile.m
00003  *  ROOTQL
00004  *
00005  *  Created by Fons Rademakers on 22/05/09.
00006  *  Copyright 2009 CERN. All rights reserved.
00007  *
00008  */
00009 
00010 #include <stdio.h>
00011 #include <fcntl.h>
00012 #include <sys/types.h>
00013 #include <sys/uio.h>
00014 #include <unistd.h>
00015 #include <stdlib.h>
00016 #include <strings.h>
00017 #include <errno.h>
00018 
00019 #import <QuickLook/QuickLook.h>
00020 #import <Cocoa/Cocoa.h>
00021 
00022 
00023 #if defined(__i386__)
00024 #   define R__BYTESWAP
00025 #endif
00026 #if defined(__x86_64__)
00027 #   define R__BYTESWAP
00028 #endif
00029 
00030 
00031 struct FileHeader_t {
00032    long long   end;
00033    long long   seekFree;
00034    long long   seekInfo;
00035    long long   seekKeys;
00036    int         version;
00037    int         begin;
00038    int         compress;
00039    int         nbytesName;
00040    int         dateC;
00041    int         timeC;
00042    int         dateM;
00043    int         timeM;
00044    char        units;
00045    char       *uuid;
00046    char       *title;
00047    const char *name;
00048 };
00049 
00050 
00051 static void FromBufChar(char **buf, char *x)
00052 {
00053    // Read a char from the buffer and advance the buffer.
00054 
00055    *x = **buf;
00056    *buf += 1;
00057 }
00058 
00059 static void FromBufShort(char **buf, short *x)
00060 {
00061    // Read a short from the buffer and advance the buffer.
00062 
00063 #ifdef R__BYTESWAP
00064    char *sw = (char *)x;
00065    sw = (*buf);
00066    sw = (*buf);
00067 #else
00068    memcpy(x, *buf, sizeof(short));
00069 #endif
00070    *buf += sizeof(short);
00071 }
00072 
00073 static void FromBufInt(char **buf, int *x)
00074 {
00075    // Read an int from the buffer and advance the buffer.
00076 
00077 #ifdef R__BYTESWAP
00078    char *sw = (char *)x;
00079    sw = (*buf);
00080    sw = (*buf);
00081    sw = (*buf);
00082    sw = (*buf);
00083 #else
00084    memcpy(x, *buf, sizeof(int));
00085 #endif
00086    *buf += sizeof(int);
00087 }
00088 
00089 static void FromBufLL(char **buf, long long *x)
00090 {
00091    // Read a long long from the buffer and advance the buffer.
00092 
00093 #ifdef R__BYTESWAP
00094    char *sw = (char *)x;
00095    sw = (*buf);
00096    sw = (*buf);
00097    sw = (*buf);
00098    sw = (*buf);
00099    sw = (*buf);
00100    sw = (*buf);
00101    sw = (*buf);
00102    sw = (*buf);
00103 #else
00104    memcpy(x, *buf, sizeof(long long));
00105 #endif
00106    *buf += sizeof(long long);
00107 }
00108 
00109 static void FromBufUUID(char **buf, char **uuid, int versiondir)
00110 {
00111    // Read UUID from the buffer and return it as string in uuid.
00112    // Returned string must be freed by the caller.
00113    // We'll never come here if version < 2.
00114 
00115    unsigned int   timeLow;
00116    unsigned short version, timeMid, timeHiAndVersion;
00117    unsigned char  clockSeqHiAndReserved, clockSeqLow, node;
00118 
00119    if (versiondir > 2)
00120       FromBufShort(buf, (short*)&version);  //version
00121    FromBufInt(buf, (int*)&timeLow);
00122    FromBufShort(buf, (short*)&timeMid);
00123    FromBufShort(buf, (short*)&timeHiAndVersion);
00124    FromBufChar(buf, (char*)&clockSeqHiAndReserved);
00125    FromBufChar(buf, (char*)&clockSeqLow);
00126    int i;
00127    for (i = 0; i < 6; i++)
00128       FromBufChar(buf, (char*)&node[i]);
00129 
00130    *uuid = malloc(40);
00131    sprintf(*uuid, "%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x",
00132            timeLow, timeMid, timeHiAndVersion, clockSeqHiAndReserved,
00133            clockSeqLow, node[0], node[1], node[2], node[3], node[4],
00134            node[5]);
00135 }
00136 
00137 static void FromBufStr(char **buf, char **str)
00138 {
00139    // Read string from the buffer and return it as string in str.
00140    // Returned string must be freed by the caller.
00141 
00142    unsigned char nwh;
00143    int           nchars;
00144 
00145    FromBufChar(buf, (char*)&nwh);
00146    if (nwh == 255)
00147       FromBufInt(buf, &nchars);
00148    else
00149       nchars = nwh;
00150 
00151    int i;
00152    *str = malloc(nchars+1);
00153    for (i = 0; i < nchars; i++)
00154       FromBufChar(buf, &(*str)[i]);
00155    (*str) = '\0';
00156 }
00157 
00158 static void GetDateAndTime(unsigned int datetime, int *date, int *time)
00159 {
00160    // Function that returns the date and time. The input is
00161    // in TDatime format (as obtained via TDatime::Get()).
00162    // Date is returned in the format 950223  February 23 1995.
00163    // Time is returned in the format 102459 10h 24m 59s.
00164 
00165    unsigned int year  = datetime>>26;
00166    unsigned int month = (datetime<<6)>>28;
00167    unsigned int day   = (datetime<<10)>>27;
00168    unsigned int hour  = (datetime<<15)>>27;
00169    unsigned int min   = (datetime<<20)>>26;
00170    unsigned int sec   = (datetime<<26)>>26;
00171    *date =  10000*(year+1995) + 100*month + day;
00172    *time =  10000*hour + 100*min + sec;
00173 }
00174 
00175 static int ReadBuffer(int fd, char *buffer, int len)
00176 {
00177    ssize_t siz;
00178    while ((siz = read(fd, buffer, len)) < 0 && errno == EINTR)
00179       errno = 0;
00180    return (int)siz;
00181 }
00182 
00183 static int ReadHeader(int fd, struct FileHeader_t *fh, NSMutableString *html)
00184 {
00185    // Read ROOT file header structure.
00186    // Returns -1 in case of error, 0 otherwise.
00187 
00188    const int len = 300;
00189    char *header = malloc(len);
00190 
00191    if (ReadBuffer(fd, header, len) != len) {
00192       free(header);
00193       return -1;
00194    }
00195 
00196    if (strncmp(header, "root", 4)) {
00197       free(header);
00198       return -1;
00199    }
00200 
00201    char *buffer = header + 4;  // skip the "root" file identifier
00202 
00203    FromBufInt(&buffer, &fh->version);
00204    FromBufInt(&buffer, &fh->begin);
00205 
00206    int dummy;
00207    long long dummyll;
00208 
00209    if (fh->version < 1000000) {
00210       // < 2GB file
00211       int seekfree, seekinfo;
00212       FromBufInt(&buffer, &dummy); fh->end = (long long) dummy;
00213       FromBufInt(&buffer, &seekfree); fh->seekFree = (long long) seekfree;
00214       FromBufInt(&buffer, &dummy); // nbytes free
00215       FromBufInt(&buffer, &dummy); // nfree
00216       FromBufInt(&buffer, &fh->nbytesName);
00217       FromBufChar(&buffer, &fh->units);
00218       FromBufInt(&buffer, &fh->compress);
00219       FromBufInt(&buffer, &seekinfo); fh->seekInfo = (long long) seekinfo;
00220       FromBufInt(&buffer, &dummy); // nbytes info
00221    } else {
00222       // > 2GB file
00223       FromBufLL(&buffer, &fh->end);
00224       FromBufLL(&buffer, &fh->seekFree);
00225       FromBufInt(&buffer, &dummy);  // nbytes free
00226       FromBufInt(&buffer, &dummy);  // nfree
00227       FromBufInt(&buffer, &fh->nbytesName);
00228       FromBufChar(&buffer, &fh->units);
00229       FromBufInt(&buffer, &fh->compress);
00230       FromBufLL(&buffer, &fh->seekInfo);
00231       FromBufInt(&buffer, &dummy);  // nbytes info
00232    }
00233 
00234    int nk = sizeof(int)+sizeof(short)+2*sizeof(int)+2*sizeof(short)+2*sizeof(int);
00235    int nbytes = fh->nbytesName + (22 + 2*sizeof(int) + 18);  //nbytesName + TDirectoryFile::Sizeof();
00236    if (fh->version >= 40000)
00237       nbytes += 12;
00238 
00239    if (nbytes + fh->begin > 300) {
00240       free(header);
00241       header = malloc(nbytes);
00242       lseek(fd, (off_t)fh->begin, SEEK_SET);
00243       if (ReadBuffer(fd, header, nbytes) != nbytes) {
00244          free(header);
00245          return -1;
00246       }
00247       buffer = header + fh->nbytesName;
00248    } else {
00249       buffer = header + fh->begin + fh->nbytesName;
00250       nk += fh->begin;
00251    }
00252 
00253    short dversion, versiondir;
00254    FromBufShort(&buffer, &dversion);
00255    versiondir = dversion%1000;
00256    FromBufInt(&buffer, &dummy);
00257    GetDateAndTime((unsigned int)dummy, &fh->dateC, &fh->timeC);
00258    FromBufInt(&buffer, &dummy);
00259    GetDateAndTime((unsigned int)dummy, &fh->dateM, &fh->timeM);
00260    FromBufInt(&buffer, &dummy);  // nbytes keys
00261    FromBufInt(&buffer, &dummy);  // nbytes name
00262    if (dversion > 1000) {
00263       FromBufLL(&buffer, &dummyll); // seek dir
00264       FromBufLL(&buffer, &dummyll); // seek parent
00265       FromBufLL(&buffer, &fh->seekKeys);
00266    } else {
00267       int skeys;
00268       FromBufInt(&buffer, &dummy); // seek dir
00269       FromBufInt(&buffer, &dummy); // seek parent
00270       FromBufInt(&buffer, &skeys); fh->seekKeys = (long long)skeys;
00271    }
00272    if (versiondir > 1)
00273       FromBufUUID(&buffer, &fh->uuid, versiondir);
00274    else
00275       fh->uuid = strdup("-");
00276 
00277    buffer = header + nk;
00278    char *str;
00279    FromBufStr(&buffer, &str); free(str);  // "TFile"
00280    FromBufStr(&buffer, &str); free(str); // orig filename
00281    FromBufStr(&buffer, &fh->title);
00282 
00283 #ifdef DEBUG
00284    NSLog(@"ReadHeader: %s, version = %d, begin = %d, end = %lld, units = %hhd, compress = %d",
00285          fh->name, fh->version, fh->begin, fh->end, fh->units, fh->compress);
00286 #endif
00287 
00288    [html appendFormat: @"<center><h3>%s</h3></center>\n", fh->name];
00289    [html appendString: @"<center>Header Summary</center><p>\n"];
00290    [html appendString: @"<table width=\"80%\" border=\"0\" cellpadding=\"2\" cellspacing=\"0\">\n"];
00291    [html appendFormat: @"<tr><td>Title:</td><td><b>%s</b></td></tr>\n", fh->title];
00292    [html appendFormat: @"<tr><td>Creation date:</td><td><b>%d/%d</b></td></tr>\n", fh->dateC, fh->timeC];
00293    [html appendFormat: @"<tr><td>Modification date:</td><td><b>%d/%d</b></td></tr>\n", fh->dateM, fh->timeM];
00294    [html appendFormat: @"<tr><td>File size (bytes):</td><td><b>%lld</b></td></tr>\n", fh->end];
00295    [html appendFormat: @"<tr><td>Compression level:</td><td><b>%d</b></td></tr>\n", fh->compress];
00296    [html appendFormat: @"<tr><td>UUID:</td><td><b>%s</b></td></tr>\n", fh->uuid];
00297    [html appendFormat: @"<tr><td>File version:</td><td><b>%d</b></td></tr>\n", fh->version];
00298    [html appendString: @"</table>\n"];
00299 
00300    free(header);
00301 
00302    return 0;
00303 }
00304 
00305 static int ReadKeys(int fd, struct FileHeader_t *fh, NSMutableString *html, QLPreviewRequestRef preview)
00306 {
00307    // Loop over all keys and print information.
00308    // Returns -1 in case of error, 0 otherwise.
00309 
00310    int    nbytes;
00311    int    objlen;
00312    int    date;
00313    int    time;
00314    short  keylen;
00315    short  cycle;
00316    char  *classname;
00317    char  *name;
00318    char  *title;
00319 
00320    const int len = 256;
00321    int   nread, datime;
00322    short versionkey;
00323    char *header, *buffer;
00324 
00325    NSDate *startDate = [NSDate date];
00326 
00327    long long idcur = fh->begin;
00328 
00329    [html appendString: @"<br>\n"];
00330    [html appendString: @"<table width=\"100%\" border=\"1\" cellpadding=\"2\" cellspacing=\"0\">\n"];
00331    [html appendString: @"<tr>\n"];
00332    [html appendString: @"<th colspan=\"7\">List of Keys</th>\n"];
00333    [html appendString: @"</tr>\n"];
00334    [html appendString: @"<tr>\n"];
00335    [html appendString: @"<th>Name</th>\n"];
00336    [html appendString: @"<th>Title</th>\n"];
00337    [html appendString: @"<th>Class</th>\n"];
00338    [html appendString: @"<th>Date</th>\n"];
00339    [html appendString: @"<th>Offset</th>\n"];
00340    [html appendString: @"<th>Size</th>\n"];
00341    [html appendString: @"<th>CX</th>\n"];
00342    [html appendString: @"</tr>\n"];
00343 
00344    nread = len;
00345    while (idcur < fh->end) {
00346    again:
00347       header = malloc(nread);
00348       lseek(fd, (off_t)idcur, SEEK_SET);
00349       if (idcur+nread > fh->end) nread = fh->end-idcur-1;
00350       if (ReadBuffer(fd, header, nread) != nread) {
00351          free(header);
00352          return -1;
00353       }
00354       buffer = header;
00355       FromBufInt(&buffer, &nbytes);
00356       if (!nbytes) {
00357          [html appendString: @"<tr>\n"];
00358          [html appendString: @"<td colspan=\"7\" style=\"color:red\"><center><b>ERROR</b></center></td>\n"];
00359          [html appendString: @"</tr>\n"];
00360          free(header);
00361          break;
00362       }
00363       if (nbytes < 0) {
00364          [html appendString: @"<tr>\n"];
00365          [html appendString: @"<td colspan=\"4\" style=\"color:red\"><center><b>GAP</b></center></td>\n"];
00366          [html appendFormat: @"<td>%lld</td>\n", idcur];
00367          [html appendFormat: @"<td>%d</td>\n", -nbytes];
00368          [html appendFormat: @"<td>%5.2f</td>\n", 1.0];
00369          [html appendString: @"<tr>\n"];
00370          free(header);
00371          idcur -= nbytes;
00372          continue;
00373       }
00374 
00375       FromBufShort(&buffer, &versionkey);
00376       FromBufInt(&buffer, &objlen);
00377       FromBufInt(&buffer, &datime);
00378       GetDateAndTime((unsigned int)datime, &date, &time);
00379       FromBufShort(&buffer, &keylen);
00380       FromBufShort(&buffer, &cycle);
00381       if (versionkey > 1000) {
00382          long long dummyll;
00383          FromBufLL(&buffer, &dummyll); // seekkey
00384          FromBufLL(&buffer, &dummyll); // seekpdir
00385       } else {
00386          int dummy;
00387          FromBufInt(&buffer, &dummy); // seekkey
00388          FromBufInt(&buffer, &dummy); // seekpdir
00389       }
00390       if (keylen > nread) {
00391          free(header);
00392          nread = keylen;
00393          goto again;
00394       }
00395       FromBufStr(&buffer, &classname);
00396       FromBufStr(&buffer, &name);
00397       FromBufStr(&buffer, &title);
00398       if (idcur == fh->seekFree) {
00399          free(classname);
00400          classname = strdup("FreeSegments");
00401          name = '\0';
00402          title = '\0';
00403       }
00404       if (idcur == fh->seekInfo) {
00405          free(classname);
00406          classname = strdup("StreamerInfo");
00407          name = '\0';
00408          title = '\0';
00409       }
00410       if (idcur == fh->seekKeys) {
00411          free(classname);
00412          classname = strdup("KeysList");
00413          name = '\0';
00414          title = '\0';
00415       }
00416       float cx;
00417       if (objlen != nbytes-keylen)
00418          cx = (float)(objlen+keylen)/(float)nbytes;
00419       else
00420          cx = 1.0;
00421 
00422       [html appendString: @"<tr>\n"];
00423       [html appendFormat: @"<td>%s</td>\n", name];
00424       [html appendFormat: @"<td>%s</td>\n", title];
00425       [html appendFormat: @"<td>%s</td>\n", classname];
00426       [html appendFormat: @"<td>%d/%d</td>\n", date, time];
00427       [html appendFormat: @"<td>%lld</td>\n", idcur];
00428       [html appendFormat: @"<td>%d</td>\n", nbytes];
00429       [html appendFormat: @"<td>%5.2f</td>\n", cx];
00430       [html appendString: @"</tr>\n"];
00431 
00432       free(classname);
00433       free(name);
00434       free(title);
00435       free(header);
00436 
00437       nread = len;
00438 
00439       idcur += nbytes;
00440 
00441       if ([startDate timeIntervalSinceNow] < -0.1) {
00442          // Check for cancel once per second
00443 #ifdef DEBUG
00444          NSLog(@"ReadKeys: checking for cancel %.3f", [startDate timeIntervalSinceNow]);
00445 #endif
00446          if (QLPreviewRequestIsCancelled(preview)) {
00447 #ifdef DEBUG
00448             NSLog(@"ReadKeys: cancelled");
00449 #endif
00450             return -1;
00451          }
00452          startDate = [startDate addTimeInterval: 0.1];
00453       }
00454    }
00455 
00456    [html appendString: @"</table>\n"];
00457 
00458    return 0;
00459 }
00460 
00461 int ReadFile(NSString *fullPath, NSMutableString *html, QLPreviewRequestRef preview)
00462 {
00463    // Read ROOT file structure for specified file.
00464    // Returns -1 in case of error, 0 otherwise.
00465 
00466    struct FileHeader_t fh;
00467    fh.name = [fullPath UTF8String];
00468    int fd = open(fh.name, O_RDONLY, 0644);
00469    if (fd == -1)
00470       return -1;
00471 
00472    if (ReadHeader(fd, &fh, html) == -1) {
00473       close(fd);
00474       return -1;
00475    }
00476 
00477    // Check for cancel
00478         if (QLPreviewRequestIsCancelled(preview)) {
00479       free(fh.uuid);
00480       free(fh.title);
00481       close(fd);
00482                 return -1;
00483         }
00484 
00485    if (ReadKeys(fd, &fh, html, preview) == -1) {
00486       free(fh.uuid);
00487       free(fh.title);
00488       close(fd);
00489       return -1;
00490    }
00491 
00492    free(fh.uuid);
00493    free(fh.title);
00494 
00495    close(fd);
00496 
00497    return 0;
00498 }

Generated on Tue Jul 5 14:44:01 2011 for ROOT_528-00b_version by  doxygen 1.5.1