C#
  1  using System;
  2  using System.IO;
  3  using System.Collections.Generic;
  4  using System.Text;
  5  
  6  namespace ReadCookie
  7  {
  8      ///
  9      /// @struct O4Cookie
 10      /// 
 11      /// @ingroup ReadCookie
 12      /// 
 13      /// @par Comments:
 14      ///         Belongs to OpraCookieJar, declared in this namespace for global
 15      ///          accessability.
 16      /// 
 17      /// @brief Opera 4 cookie data structure
 18      /// 
 19      public struct O4Cookie
 20      {
 21          public string Name;
 22          public string Value;
 23          public string Comment;
 24          public string CommentURL;
 25          public string RecvDomain;
 26          public string RecvPath;
 27          public string PortList;
 28          public byte Version;
 29          public bool Authenticate;
 30          public bool Server;
 31          public bool Secure;
 32          public bool Protected;
 33          public bool ThirdParty;
 34          public bool Password;
 35          public bool Prefixed;
 36          public ulong Expires;
 37          public ulong LastUsed;
 38      }
 39  
 40      //////////////////////////////////////////////////////////////////////////////
 41      ///
 42      /// @brief      Cookie handling functionality for Opera version 4 cookies.
 43      ///              Class provides means for parsing the cookie data,
 44      ///              as well as exposing all data as class objects.
 45      ///
 46      /// @ingroup    ReadCookie
 47      /// 
 48      /// @par Comments:
 49      ///         Initial concept borrowed from Delphi source posted to Experts Exchange by Russell Libby,
 50      ///         see: http://www.experts-exchange.com/Programming/Languages/Pascal/Delphi/Q_20865505.html.
 51      ///         This implementation only provides for reading of the cookie file.
 52      /// 
 53      /// @par References:
 54      ///         While this site did not provide any source code (other
 55      ///         than constant values) to go from, it did provide valuable
 56      ///         technical information in regards to the parsing of the
 57      ///         cookies4.dat file.
 58      ///         http://users.westelcom.com/jsegur/O4FE.HTM#TS1
 59      ///
 60      ///         Opera's Technical documentation can be found at:
 61      ///         http://www.opera.com/docs/fileformats
 62      /// 
 63      /// @author David MacDermot
 64      /// 
 65      /// @date 07-07-11
 66      /// 
 67      /// @todo   GMT Handling:  The O4Cookie exposes dates using the LongWord value
 68      ///          which is the GMT from 1/1/1970. Need to add utility
 69      ///          routines that will convert the LongWord values to
 70      ///          the a DateTime (local date/time).
 71      ///
 72      /// @bug 
 73      ///
 74      //////////////////////////////////////////////////////////////////////////////
 75  
 76      public class OpraCookieJar
 77      {
 78  
 79          private byte[] _RawBytes;
 80          private O4Domain _Root;
 81  
 82          #region Opera cookie format elements
 83  
 84          ////////////////////////////////////////////////////////////////////////////////
 85          //   Opera 4 cookie version constants
 86          ////////////////////////////////////////////////////////////////////////////////
 87          const uint O4_VER_FILE = 0x00001000;
 88          const uint O4_VER_APP = 0x00002001;
 89  
 90          ////////////////////////////////////////////////////////////////////////////////
 91          //   Opera 4 valid cookie header (Little Endian)
 92          ////////////////////////////////////////////////////////////////////////////////
 93          private static O4CookieHeader CookieFileHeader;
 94  
 95          ////////////////////////////////////////////////////////////////////////////////
 96          // Opera 4 cookie domain tag id constants
 97          ////////////////////////////////////////////////////////////////////////////////
 98  
 99          // Domain start tag
100          const byte O4_ID_DMN = 0x01;
101  
102          // Domain element name (string).
103          const byte O4_ID_DMN_NAME = 0x1E;
104  
105          // Cookie server accept flags. Content is a numerical value:
106          // 1 = Accept all from domain.
107          // 2 = Refuse all from domain.
108          // 3 = Accept all from server.
109          // 4 = Refuse all from server.
110          const byte O4_ID_DMN_FILTER = 0x1F;
111  
112          // Cookie with path not matching:
113          // 1 = Refuse.
114          // 2 = Accept automatically.
115          const byte O4_ID_DMN_MATCH = 0x21;
116  
117          // Third party cookie handling:
118          // 1 = Accept all from domain.
119          // 2 = Refuse all from domain.
120          // 3 = Accept all from server.
121          // 4 = Refuse all from server.
122          const byte O4_ID_DMN_ACCEPT = 0x25;
123  
124          // End of domain flag
125          const byte O4_ID_DMN_END = 0x84;
126  
127          ////////////////////////////////////////////////////////////////////////////////
128          // Opera 4 cookie path tag id constants
129          ////////////////////////////////////////////////////////////////////////////////
130  
131          // Path start tag
132          const byte O4_ID_PATH = 0x02;
133  
134          // Path element name (string).
135          const byte O4_ID_PATH_NAME = 0x1D;
136  
137          // End of path flag
138          const byte O4_ID_PATH_END = 0x85;
139  
140          ////////////////////////////////////////////////////////////////////////////////
141          // Opera 4 cookie tag id constants
142          ////////////////////////////////////////////////////////////////////////////////
143  
144          // Cookie start tag
145          const byte O4_ID_COOKIE = 0x03;
146  
147          // Cookie name (string)
148          const byte O4_ID_COOKIE_NAME = 0x10;
149  
150          // Cookie value (string)
151          const byte O4_ID_COOKIE_VALUE = 0x11;
152  
153          // Cookie expires (time)
154          const byte O4_ID_COOKIE_EXPIRES = 0x12;
155  
156          // Cookie last used (time)
157          const byte O4_ID_COOKIE_USED = 0x13;
158  
159          // Cookie2 comment (string)
160          const byte O4_ID_COOKIE_DESC = 0x14;
161  
162          // Cookie2 Comment URL (string)
163          const byte O4_ID_COOKIE_DESCURL = 0x15;
164  
165          // Cookie2 Received Domain (string)
166          const byte O4_ID_COOKIE_RXDMN = 0x16;
167  
168          // Cookie2 Received Path (string)
169          const byte O4_ID_COOKIE_RXPATH = 0x17;
170  
171          // Cookie2 Portlist (string)
172          const byte O4_ID_COOKIE_PORT = 0x18;
173  
174          // Cookie secure flag (true if present)
175          const byte O4_ID_COOKIE_SECURE = 0x99;
176  
177          // Cookie Version (unsigned numerical)
178          const byte O4_ID_COOKIE_VER = 0x1A;
179  
180          // Cookie sent back to server that sent it (true if present)
181          const byte O4_ID_COOKIE_SERVER = 0x9B;
182  
183          // Cookie protected flag   (true if present)
184          const byte O4_ID_COOKIE_PROTECT = 0x9C;
185  
186          // Cookie Path prefix flag (true if present)
187          const byte O4_ID_COOKIE_PREFIX = 0xA0;
188  
189          // Cookie Password Flag (true if present)
190          const byte O4_ID_COOKIE_PWD = 0xA2;
191  
192          // Cookie Authenticate Flag (true if present)
193          const byte O4_ID_COOKIE_AUTH = 0xA3;
194  
195          // Cookie Third party flag (true if present)
196          const byte O4_ID_COOKIE_3RD = 0xA4;
197  
198          // End of cookie flag (true if present)
199          const byte O4_ID_COOKIE_END = 0xA9; //undocumented - educated guess
200  
201          #endregion //Opera cookie format elements
202  
203          #region Utilities
204  
205          //////////////////////////////////////////////////////////////////////////////
206          ///
207          /// @brief      A utility class for swapping values between big and little endian.
208          ///
209          /// @ingroup    OpraCookieJar
210          ///
211          /// @author David MacDermot
212          /// 
213          /// @date 07-07-11
214          /// 
215          /// @todo 
216          ///
217          /// @bug 
218          ///
219          //////////////////////////////////////////////////////////////////////////////
220  
221          internal class Endian
222          {
223              private static readonly bool _LittleEndian;
224  
225              ///
226              ///  @brief Class constructor.
227              /// 
228              ///  @return The static instance of the class.
229              ///
230              static Endian()
231              {
232                  _LittleEndian = BitConverter.IsLittleEndian;
233              }
234  
235              ///
236              ///  @brief Swap a short.
237              /// 
238              ///  @param v The value to swap.
239              /// 
240              ///  @return short The swapped value.
241              ///
242              public static short SwapInt16(short v)
243              {
244                  return (short)(((v & 0xff) << 8) | ((v >> 8) & 0xff));
245              }
246  
247              ///
248              ///  @brief Swap an unsigned short.
249              /// 
250              ///  @param v The value to swap.
251              /// 
252              ///  @return short The swapped value.
253              ///
254              public static ushort SwapUInt16(ushort v)
255              {
256                  return (ushort)(((v & 0xff) << 8) | ((v >> 8) & 0xff));
257              }
258  
259              ///
260              ///  @brief Swap an int.
261              /// 
262              ///  @param v The value to swap.
263              /// 
264              ///  @return short The swapped value.
265              ///
266              public static int SwapInt32(int v)
267              {
268                  return (int)(((SwapInt16((short)v) & 0xffff) << 0x10) |
269                                (SwapInt16((short)(v >> 0x10)) & 0xffff));
270              }
271  
272              ///
273              ///  @brief Swap an unsigned int.
274              /// 
275              ///  @param v The value to swap.
276              /// 
277              ///  @return short The swapped value.
278              ///
279              public static uint SwapUInt32(uint v)
280              {
281                  return (uint)(((SwapUInt16((ushort)v) & 0xffff) << 0x10) |
282                                 (SwapUInt16((ushort)(v >> 0x10)) & 0xffff));
283              }
284  
285              ///
286              ///  @brief Swap a long.
287              /// 
288              ///  @param v The value to swap.
289              /// 
290              ///  @return short The swapped value.
291              ///
292              public static long SwapInt64(long v)
293              {
294                  return (long)(((SwapInt32((int)v) & 0xffffffffL) << 0x20) |
295                                 (SwapInt32((int)(v >> 0x20)) & 0xffffffffL));
296              }
297  
298              ///
299              ///  @brief Swap an unsigned long.
300              /// 
301              ///  @param v The value to swap.
302              /// 
303              ///  @return short The swapped value.
304              ///
305              public static ulong SwapUInt64(ulong v)
306              {
307                  return (ulong)(((SwapUInt32((uint)v) & 0xffffffffL) << 0x20) |
308                                  (SwapUInt32((uint)(v >> 0x20)) & 0xffffffffL));
309              }
310  
311              ///
312              ///  @brief returns true if operating system is Big Endian.
313              ///
314              public static bool IsBigEndian
315              {
316                  get { return !_LittleEndian; }
317              }
318  
319              ///
320              ///  @brief returns true if operating system is Little Endian.
321              ///
322              public static bool IsLittleEndian
323              {
324                  get { return _LittleEndian; }
325              }
326          }
327  
328          #endregion //Utilities
329  
330          #region Data Structures
331  
332          ///
333          /// @struct O4CookieHeader
334          /// 
335          /// @ingroup OpraCookieJar
336          /// 
337          /// @brief Opera 4 cookie header
338          ///
339          private struct O4CookieHeader
340          {
341              public uint dwFileVer;
342              public uint dwAppVer;
343              public ushort wTagSize;
344              public ushort wRecSize;
345  
346              ///
347              ///  @brief Struct initializer.
348              /// 
349              ///  @return void.
350              ///
351              public void Initialize()
352              {
353                  this.dwFileVer = O4_VER_FILE;
354                  this.dwAppVer = O4_VER_APP;
355                  this.wTagSize = 1;
356                  this.wRecSize = 2;
357              }
358  
359              ///
360              ///  @brief Populate struct fields from initial header bytes of cookies.dat data.
361              /// 
362              ///  @param bData The data bytes read from cookies.dat file.
363              ///  @param idx The address of an integer with the current index position.
364              /// 
365              ///  @return void.
366              ///
367              public void Load(byte[] bData, ref int idx)
368              {
369                  this.dwFileVer = Endian.SwapUInt32(BitConverter.ToUInt32(bData, idx));
370                  idx += 4;
371                  this.dwAppVer = Endian.SwapUInt32(BitConverter.ToUInt32(bData, idx));
372                  idx += 4;
373                  this.wTagSize = Endian.SwapUInt16(BitConverter.ToUInt16(bData, idx));
374                  idx += 2;
375                  this.wRecSize = Endian.SwapUInt16(BitConverter.ToUInt16(bData, idx));
376                  idx += 2;
377              }
378  
379              ///
380              ///  @brief Save struct field header bytes to cookies.dat data.
381              /// 
382              ///  @param bData The data byte buffer to be written to the cookies.dat file.
383              ///  @param idx The address of an integer with the current index position.
384              /// 
385              ///  @return void.
386              ///
387              public void Save(byte[] bData, ref int idx)
388              {
389                  BitConverter.GetBytes(Endian.SwapUInt32(this.dwFileVer)).CopyTo(bData, idx);
390                  idx += 4;
391                  BitConverter.GetBytes(Endian.SwapUInt32(this.dwAppVer)).CopyTo(bData, idx);
392                  idx += 4;
393                  BitConverter.GetBytes(Endian.SwapUInt16(this.wTagSize)).CopyTo(bData, idx);
394                  idx += 2;
395                  BitConverter.GetBytes(Endian.SwapUInt16(this.wRecSize)).CopyTo(bData, idx);
396                  idx += 2;
397              }
398          }
399  
400          ///
401          /// @struct O4CookieHeader
402          /// 
403          /// @ingroup OpraCookieJar
404          /// 
405          /// @brief Opera 4 cookie domain data structure
406          ///
407          private struct O4Domain
408          {
409              public List<O4Domain> FDomains;
410              public string FName;
411              public byte FFilter;
412              public byte FMatch;
413              public byte FAccept;
414              public Dictionary<string, string> FPaths;
415              public List<O4Cookie> FCookies;
416  
417              ///
418              ///  @brief Struct initializer overload.
419              /// 
420              ///  @param Name The domain name.
421              /// 
422              ///  @return void.
423              ///
424              public void initialize(string Name)
425              {
426                  FName = Name;
427                  this.initialize();
428              }
429  
430              ///
431              ///  @brief Struct initializer.
432              /// 
433              ///  @return void.
434              ///
435              public void initialize()
436              {
437                  FDomains = new List<O4Domain>();
438                  FPaths = new Dictionary<string, string>();
439                  FCookies = new List<O4Cookie>();
440              }
441          }
442  
443          #endregion //Data Structures
444  
445          #region Parser
446  
447          ///
448          ///  @brief Parse file bytes into searchable memory tree.
449          /// 
450          ///  @param domain A pointer to an O4Domain struct.
451          ///  @param b The file bytes to parse.
452          ///  @param idx The address of an integer with the current index position.
453          /// 
454          ///  @return void.
455          ///
456          private void ParseCookieBytes(ref O4Domain domain, byte[] b, ref int idx)
457          {
458              ushort wTagLen;
459              byte cbTagID;
460  
461              // Keep reading tags in
462              while (idx < b.Length)
463              {
464                  cbTagID = b[idx++];
465  
466                  // Handle the tag
467                  switch (cbTagID)
468                  {
469                      case O4_ID_DMN: // Sub-domain
470  
471                          // Load the domain tag size
472                          wTagLen = Endian.SwapUInt16(BitConverter.ToUInt16(b, idx));
473                          idx += 2;
474  
475                          // Tag indicates how many bytes we should read. We don"t go by this,
476                          // because then we lose context of who the record belongs to. For( example,
477                          // there may be sub-domains, cookies, etc below this domain. Due to this,
478                          // we can't really break when we have read the content bytes of the domain.
479  
480                          O4Domain d = new O4Domain();
481                          d.initialize();
482                          ParseCookieBytes(ref d, b, ref idx);
483                          domain.FDomains.Add(d);
484                          break;
485  
486                      case O4_ID_DMN_NAME: // Domain name string
487                          domain.FName = this.ReadString(b, ref idx);
488                          break;
489  
490                      case O4_ID_DMN_FILTER: // Domain filter value
491                          domain.FFilter = this.ReadByte(b, ref idx);
492                          break;
493  
494                      case O4_ID_DMN_MATCH: // Domain match value
495                          domain.FMatch = this.ReadByte(b, ref idx);
496                          break;
497  
498                      case O4_ID_DMN_ACCEPT: // Domain accept value
499                          domain.FAccept = this.ReadByte(b, ref idx);
500                          break;
501  
502                      case O4_ID_DMN_END: // End of domain record
503                          return;
504  
505                      case O4_ID_PATH: // Start of path
506                          break;
507  
508                      case O4_ID_PATH_NAME: // Path name string
509                          domain.FPaths.Add(this.ReadString(b, ref idx), string.Empty);
510                          break;
511  
512                      case O4_ID_PATH_END: // Path end
513                          break; //Sub domain end
514  
515                      case O4_ID_COOKIE: // Cookie
516                          AddCookie(ref domain, b, ref idx);
517                          break;
518  
519                      default:
520                          if (!(0 < (cbTagID & 0x80))) // this is a field tag
521                          {
522                              // Increment to next field
523                              idx += (2 + Endian.SwapUInt16(BitConverter.ToUInt16(b, idx)));
524                          }
525                          // Ignore undocumented flags (already incremented one byte)
526                          break;
527                  }
528              }
529          }
530  
531          ///
532          ///  @brief Add cookie record to searchable memory tree.
533          /// 
534          ///  @param domain A pointer to an O4Domain struct (parent node).
535          ///  @param b The file bytes to parse.
536          ///  @param idx The address of an integer with the current index position.
537          /// 
538          ///  @return void.
539          ///
540          private void AddCookie(ref O4Domain domain, byte[] b, ref int idx)
541          {
542              ushort wTagLen;
543              byte cbTagID;
544  
545              O4Cookie cookie = new O4Cookie();
546  
547              // Load the cookie tag size
548              wTagLen = Endian.SwapUInt16(BitConverter.ToUInt16(b, idx));
549              idx += 2;
550  
551              // Tag indicates how many bytes we should read.  We don't go by this,
552              // because then we lose context of who the record belongs to.
553  
554              // Keep reading tags in
555              while (idx < b.Length)
556              {
557                  cbTagID = b[idx++];
558  
559                  // Handle the tag
560                  switch (cbTagID)
561                  {
562                      case O4_ID_COOKIE_NAME:// Cookie name
563                          cookie.Name = this.ReadString(b, ref idx);
564                          break;
565  
566                      case O4_ID_COOKIE_VALUE:// Cookie value
567                          cookie.Value = this.ReadString(b, ref idx);
568                          break;
569  
570                      case O4_ID_COOKIE_EXPIRES:// Cookie expires
571                          cookie.Expires = this.ReadLong(b, ref idx);
572                          break;
573  
574                      case O4_ID_COOKIE_USED:// Cookie last used
575                          cookie.LastUsed = this.ReadLong(b, ref idx);
576                          break;
577  
578                      case O4_ID_COOKIE_DESC:// Cookie2 comment
579                          cookie.Comment = this.ReadString(b, ref idx);
580                          break;
581  
582                      case O4_ID_COOKIE_DESCURL:// Cookie2 Comment URL
583                          cookie.CommentURL = this.ReadString(b, ref idx);
584                          break;
585  
586                      case O4_ID_COOKIE_RXDMN:// Cookie2 Received Domain
587                          cookie.RecvDomain = this.ReadString(b, ref idx);
588                          break;
589  
590                      case O4_ID_COOKIE_RXPATH:// Cookie2 Received Path
591                          cookie.RecvPath = this.ReadString(b, ref idx);
592                          break;
593  
594                      case O4_ID_COOKIE_PORT:// Cookie2 Portlist
595                          cookie.PortList = this.ReadString(b, ref idx);
596                          break;
597  
598                      case O4_ID_COOKIE_SECURE:// Cookie secure flag
599                          cookie.Secure = true;
600                          break;
601  
602                      case O4_ID_COOKIE_VER:// Cookie Version
603                          cookie.Version = this.ReadByte(b, ref idx);
604                          break;
605  
606                      case O4_ID_COOKIE_SERVER:// Cookie sent back to server that sent it
607                          cookie.Server = true;
608                          break;
609  
610                      case O4_ID_COOKIE_PROTECT:// Cookie protected flag
611                          cookie.Protected = true;
612                          break;
613  
614                      case O4_ID_COOKIE_PREFIX:// Cookie Path prefix flag
615                          cookie.Prefixed = true;
616                          break;
617  
618                      case O4_ID_COOKIE_PWD:// Cookie Password Flag
619                          cookie.Password = true;
620                          break;
621  
622                      case O4_ID_COOKIE_AUTH:// Cookie Authenticate Flag
623                          cookie.Authenticate = true;
624                          break;
625  
626                      case O4_ID_COOKIE_3RD:// Cookie Third party flag
627                          cookie.ThirdParty = true;
628                          break;
629  
630                      case O4_ID_COOKIE_END:
631                          goto EXIT_WHILE;
632  
633                      default:// Handle undocumented flags and field tags
634                          if (!(0 < (cbTagID & 0x80))) // this is a field tag
635                          {
636                              // Increment to next field
637                              idx += (2 + Endian.SwapUInt16(BitConverter.ToUInt16(b, idx)));
638                          }
639                          // Ignore undocumented flags (already incremented one byte)
640                          break;
641                  }
642              }
643          EXIT_WHILE:
644              domain.FCookies.Add(cookie);
645          }
646  
647          ///
648          ///  @brief Read a string field from the file bytes.
649          /// 
650          ///  @param b The file bytes to parse.
651          ///  @param idx The address of an integer with the current index position.
652          /// 
653          ///  @return void.
654          ///
655          private string ReadString(byte[] b, ref int idx)
656          {
657              ushort wStrLen = 0;
658  
659              // Set default
660              string lpszStr = string.Empty;
661              ASCIIEncoding encoding = new ASCIIEncoding();
662  
663              // Read a string value from the stream
664              wStrLen = Endian.SwapUInt16(BitConverter.ToUInt16(b, idx));
665              idx += 2;
666              if (0 < wStrLen)
667              {
668                  // Allocate string to read in
669                  lpszStr = encoding.GetString(b, idx, wStrLen);
670                  idx += wStrLen;
671              }
672  
673              // Return string value
674              return lpszStr;
675          }
676  
677          ///
678          ///  @brief Read an unsigned long field from the file bytes.
679          /// 
680          ///  @param b The file bytes to parse.
681          ///  @param idx The address of an integer with the current index position.
682          /// 
683          ///  @return void.
684          ///
685          private ulong ReadLong(byte[] b, ref int idx)
686          {
687              ushort wIntLen = 0;
688  
689              // Set default
690              ulong dwRtn = 0;
691  
692              // Read the length field value
693              wIntLen = Endian.SwapUInt16(BitConverter.ToUInt16(b, idx));
694              idx += 2;
695              if (0 < wIntLen)
696              {
697                  // Read single long
698                  dwRtn = Endian.SwapUInt64(BitConverter.ToUInt64(b, idx));
699                  idx += 8;
700              }
701              return dwRtn;
702          }
703  
704          ///
705          ///  @brief Read a single byte field from the file bytes.
706          /// 
707          ///  @param b The file bytes to parse.
708          ///  @param idx The address of an integer with the current index position.
709          /// 
710          ///  @return void.
711          ///
712          private byte ReadByte(byte[] b, ref int idx)
713          {
714              ushort wByteLen = 0;
715  
716              // Set default
717              byte bRtn = 0;
718  
719              // Read the length field value
720              wByteLen = Endian.SwapUInt16(BitConverter.ToUInt16(b, idx));
721              idx += 2;
722              if (0 < wByteLen)
723              {
724                  // Read single byte
725                  bRtn = b[idx++];
726              }
727              return bRtn;
728          }
729  
730          #endregion //Parser
731  
732          #region Class Constructor
733  
734          ///
735          ///  @brief Class constructor.
736          /// 
737          ///  @return An instance of the class.
738          ///
739          public OpraCookieJar() { }
740  
741          ///
742          ///  @brief Class constructor overload.
743          /// 
744          ///  @param Bytes The file bytes streamed from cookies.dat
745          /// 
746          ///  @return An instance of the class.
747          ///
748          public OpraCookieJar(byte[] Bytes)
749          {
750              _RawBytes = Bytes;
751          }
752  
753          ///
754          ///  @brief Class constructor overload.
755          /// 
756          ///  @param FilePath The file path string for cookies.dat
757          /// 
758          ///  @return An instance of the class.
759          ///
760          public OpraCookieJar(string FilePath)
761          {
762              string strTemp;
763              FileStream f;
764              FileInfo fi;
765              ASCIIEncoding encoder;
766              try
767              {
768                  byte[] bytes;
769  
770                  encoder = new ASCIIEncoding();
771                  strTemp = FilePath + ".temp";
772  
773                  // First copy the cookie jar so that we can read the cookies from unlocked copy while
774                  // Opera is running
775                  File.Copy(FilePath, strTemp, true);
776  
777                  // Read Temp
778                  fi = new FileInfo(strTemp);
779                  bytes = new byte[fi.Length];
780                  f = fi.OpenRead();
781                  f.Read(bytes, 0, bytes.Length);
782                  f.Close();
783  
784                  // Delete temp
785                  File.Delete(strTemp);
786  
787                  //Load the class
788                  RawBytes = bytes;
789              }
790              catch (Exception)
791              {
792                  throw;
793              }
794          }
795  
796          #endregion //Class Constructor
797  
798          #region Properties
799  
800          ///
801          ///  @brief Gets or sets the file bytes streamed from cookies.dat.
802          ///
803          public byte[] RawBytes
804          {
805              get { return _RawBytes; }
806              set
807              {
808                  _RawBytes = value;
809  
810                  int idx = 0;
811                  CookieFileHeader.Load(_RawBytes, ref idx);
812                  _Root = new O4Domain();
813                  _Root.initialize("Root");
814                  ParseCookieBytes(ref _Root, _RawBytes, ref idx);
815              }
816          }
817  
818          #endregion //Properties
819  
820          ///
821          ///  @brief Recursive search function employed by GetCookies.
822          /// 
823          ///  @param Domain The current domain to search.
824          ///  @param Names The array of domain names to find.
825          ///  @param iName The index of the name to reference in the search.
826          ///
827          ///  @return A list of O4Cookie objects if successfull, otherwise null.
828          ///
829          private List<O4Cookie> GetCookieRecurse(O4Domain Domain, string[] Names, int iName)
830          {
831              List<O4Cookie> ret = null;
832  
833              if (iName < Names.Length)
834              {
835                  foreach (O4Domain d in Domain.FDomains)
836                  {
837                      if (d.FName.ToUpper().Equals(Names[iName].ToUpper())) //Match, search for next domain
838                      {
839                          ret = GetCookieRecurse(d, Names, iName + 1);
840                      }
841                      else //Search the next level down for this domain
842                      {
843                          ret = GetCookieRecurse(d, Names, iName);
844                      }
845  
846                      if (ret != null)
847                          return ret;
848                  }
849              }
850              else //We incremented to the end of the domain get the cookies
851              {
852                  if (0 < Domain.FCookies.Count)
853                  {
854                      return Domain.FCookies;
855                  }
856              }
857              return null; // If we get here we couldn't find it
858          }
859  
860          ///
861          ///  @brief Search memory tree for cookies stored under the domain name of
862          ///          a given server.
863          /// 
864          ///  @param HostName The domain name to search for.
865          ///
866          ///  @return A list of O4Cookie objects if successfull, otherwise null.
867          ///
868          public List<O4Cookie> GetCookies(string HostName)
869          {
870              List<O4Cookie> cookies = null;
871              string[] aryNames = HostName.Split('.');
872              Array.Reverse(aryNames);
873  
874              // Search for host
875              cookies = GetCookieRecurse(_Root, aryNames, 0);
876              return cookies;
877          }
878      }
879  }