00001
00002
00003
00004
00005
00006
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
00054
00055 *x = **buf;
00056 *buf += 1;
00057 }
00058
00059 static void FromBufShort(char **buf, short *x)
00060 {
00061
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
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
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
00112
00113
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);
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
00140
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
00161
00162
00163
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
00186
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;
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
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);
00215 FromBufInt(&buffer, &dummy);
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);
00221 } else {
00222
00223 FromBufLL(&buffer, &fh->end);
00224 FromBufLL(&buffer, &fh->seekFree);
00225 FromBufInt(&buffer, &dummy);
00226 FromBufInt(&buffer, &dummy);
00227 FromBufInt(&buffer, &fh->nbytesName);
00228 FromBufChar(&buffer, &fh->units);
00229 FromBufInt(&buffer, &fh->compress);
00230 FromBufLL(&buffer, &fh->seekInfo);
00231 FromBufInt(&buffer, &dummy);
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);
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);
00261 FromBufInt(&buffer, &dummy);
00262 if (dversion > 1000) {
00263 FromBufLL(&buffer, &dummyll);
00264 FromBufLL(&buffer, &dummyll);
00265 FromBufLL(&buffer, &fh->seekKeys);
00266 } else {
00267 int skeys;
00268 FromBufInt(&buffer, &dummy);
00269 FromBufInt(&buffer, &dummy);
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);
00280 FromBufStr(&buffer, &str); free(str);
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
00308
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);
00384 FromBufLL(&buffer, &dummyll);
00385 } else {
00386 int dummy;
00387 FromBufInt(&buffer, &dummy);
00388 FromBufInt(&buffer, &dummy);
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
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
00464
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
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 }