1//  This code demonstrates:
2//
3//  - A class derived from c4_Strategy to implement encrypted storage.
4//  - Disabling the Flush calls issued during Commit() for speed.
5//  - Using c4_Strategy objects as the basis of all file I/O in Metakit.
6
7#include "mk4.h"
8#include "mk4io.h"
9
10#include <string.h>
11
12/////////////////////////////////////////////////////////////////////////////
13// This derived strategy encrypts its data on disk and omits flushes
14
15class CEncryptStrategy : public c4_FileStrategy
16{
17public:
18  CEncryptStrategy (const char* fileName_, bool rw_);
19  virtual ~CEncryptStrategy ();
20
21  // Reading and writing of course messes around with all the data
22  virtual int  DataRead(long, void*, int);
23  virtual void DataWrite(long, const void*, int);
24
25  // For this example, we also disable all explicit file flushes
26  virtual void DataCommit(long) { }
27
28  // Cannot use memory mapped file access when decoding on the fly
29  virtual void ResetFileMapping() { }
30
31private:
32  // This example uses a trivial encoding, incorporating offsets.
33  static char Encode(long pos, char c_)
34    { return (char) (c_ ^ pos ^ 211); }
35  static char Decode(long pos, char c_)
36    { return (char) (c_ ^ pos ^ 211); }
37};
38
39CEncryptStrategy::CEncryptStrategy (const char* fileName_, bool rw_)
40{
41  c4_FileStrategy::DataOpen(fileName_, rw_);
42}
43
44CEncryptStrategy::~CEncryptStrategy ()
45{
46}
47
48int CEncryptStrategy::DataRead(long lOff, void* lpBuf, int nCount)
49{
50  int result = 0;
51
52  if (nCount > 0)
53  {
54    char* ptr = (char*) lpBuf;
55
56    result = c4_FileStrategy::DataRead(lOff, ptr, nCount);
57
58    for (int i = 0; i < result; ++i)
59      ptr[i] = Decode(lOff++, ptr[i]);
60  }
61
62  return result;
63}
64
65void CEncryptStrategy::DataWrite(long lOff, const void* lpBuf, int nCount)
66{
67  if (nCount > 0)
68  {
69    c4_Bytes buf;
70    char* ptr = (char*) buf.SetBuffer(nCount);
71
72    memcpy(ptr, lpBuf, nCount);
73
74    for (int i = 0; i < nCount; ++i)
75      ptr[i] = Encode(lOff++, ptr[i]);
76
77    c4_FileStrategy::DataWrite(lOff - nCount, ptr, nCount);
78  }
79}
80
81/////////////////////////////////////////////////////////////////////////////
82
83int main()
84{
85  // This property could just as well have been declared globally.
86  c4_StringProp pLine ("line");
87
88  {
89      // This is where the magic takes place.
90    CEncryptStrategy efile ("secret.dat", true);
91
92    c4_Storage storage (efile);
93
94    static const char* message[] = {
95      "This is a small message which will be encrypted on file.",
96      "As a result, none of the other Metakit utilities can read it.",
97      "Furthermore, a hex dump of this file will produce gibberish.",
98      "The encryption used here is ridiculously simple, however.",
99      "Beware of naive encryption schemes, cracking them is a sport.",
100      0
101    };
102
103      // Store the text lines as separate entries in the view.
104    c4_View vText;
105
106    for (const char** p = message; *p; ++p)
107      vText.Add(pLine [*p]);
108
109      // changed 2000-03-15: Store is gone
110    //storage.Store("text", vText);
111    c4_View v2 = storage.GetAs("text[line:S]");
112    v2.InsertAt(0, vText);
113
114    storage.Commit();
115  }
116
117  // The end of the preceding block will flush out all data to file.
118  {
119      // Repeat the process when accessing the encrypted file again.
120    CEncryptStrategy efile ("secret.dat", false);
121
122    c4_Storage storage (efile);
123    c4_View vText = storage.View("text");
124
125    for (int i = 0; i < vText.GetSize(); ++i)
126    {
127      const char* s = pLine (vText[i]);
128      puts(s);
129    }
130  }
131
132  // At this point, an encrypted data file is left behind on the disk.
133
134  return 0;
135}
136
137/////////////////////////////////////////////////////////////////////////////
138