summaryrefslogtreecommitdiff
path: root/plugins/MirandaNGHistoryToDB/MapStream.pas
blob: af0b67409a2fb380647f3a6f3cdd1a84f9d15c64 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
{ ############################################################################ }
{ #                                                                          # }
{ #  MirandaNG HistoryToDB Plugin v2.5                                       # }
{ #                                                                          # }
{ #  License: GPLv3                                                          # }
{ #                                                                          # }
{ #  Author: Grigorev Michael (icq: 161867489, email: sleuthhound@gmail.com) # }
{ #                                                                          # }
{ ############################################################################ }

//*****************************************************************//
//                                                                 //
//  TMapStream                                                     //
//  Copyright© BrandsPatch LLC                                     //
//  http://www.explainth.at                                        //
//                                                                 //
//  All Rights Reserved                                            //
//                                                                 //
//  Permission is granted to use, modify and redistribute          //
//  the code in this Delphi unit on the condition that this        //
//  notice is retained unchanged.                                  //
//                                                                 //
//  BrandsPatch declines all responsibility for any losses,        //
//  direct or indirect, that may arise  as a result of using       //
//  this code.                                                     //
//                                                                 //
//*****************************************************************//
unit MapStream;

interface

uses Windows, SysUtils, Classes, SyncObjs;

const MAXINTMINUS = MAXINT - 1;

type TMapBytes = array[0..MAXINTMINUS] of Byte;
     PMapBytes = ^TMapBytes;

type TMapStream = class(TObject)
private
  FHandle: THandle;
  FPosition: Integer;
  FSize: Integer;
  FTimeOut: Integer;
  procedure SetPosition(Value: Integer);
  function CountGood(Count: Integer):Boolean;
  function GrabEvent: Boolean;
  procedure ReleaseEvent;
protected
  FEvent: TEvent;
  FMemory: PMapBytes;
public
  property Position: Integer read FPosition write SetPosition;
  constructor CreateEx(const AName: String; ASize,ATimeOut: Integer);
  destructor Destroy; override;
  function Clear: Boolean;
  function CopyFrom(AStream: TStream;Count: Integer): Boolean;
  function ReadBuffer(P: Pointer; Count: Integer): Boolean;
  function WriteBuffer(P: Pointer; Count: Integer): Boolean;
end;

type ENoMapping = class(Exception);

implementation

// MapStream Create & Destroy
constructor TMapStream.CreateEx(const AName:String;ASize,ATimeOut:Integer);
begin
  inherited Create;
  FSize := ASize;
  FTimeOut := ATimeOut;
  if (FSize < 1) or (FSize > MAXINTMINUS) then FSize:=MAXWORD;
  if (FTimeOut < 1) or (FTimeOut > 5000) then FTimeOut:=2000;
  //2000ms timeout for safety
  FHandle:=CreateFileMapping($FFFFFFFF,nil,PAGE_READWRITE,0,FSize,PChar(AName));
  //See the Windows Kernel32 CreateFileMapping function for information
  if (FHandle = 0) then ENoMapping.Create(Format('%s file mapping failed.',[AName]))
  else begin
    FMemory:=MapViewOfFile(FHandle,FILE_MAP_ALL_ACCESS,0,0,0);

    FEvent:=TEvent.Create(nil,True,True,Format('ExplainThat_%s_MAP',[AName]));
    {1. map a view of the file mapping into the address
        space of the parent application

    2.  create an event to prevent simultaneous access
        to the map by different apps. We try to make the
        event name unique so we don't end up with a handle to
        an unrelated event that already exists
    }
  end;
end;

destructor TMapStream.Destroy;
begin
  UnMapViewOfFile(FMemory);
  CloseHandle(FHandle);
  FEvent.Free;
  inherited;
end;

function TMapStream.CountGood(Count:Integer):Boolean;
begin
  Result:=(FPosition + Count < FSize);
end;

function TMapStream.GrabEvent:Boolean;
begin
  Result:=True;
  with FEvent do
  begin
    case WaitFor(FTimeOut) of
      wrSignaled:ReSetEvent;
      {locks the event for exclusive use by this app. Funny name, ReSetEvent, not
       our choice!}
      else Result:=False;
    end;
  end;
end;

procedure TMapStream.ReleaseEvent;
begin
  FEvent.SetEvent; //unlock the event so other apps can use it
end;

// MapStream Manipulation
function TMapStream.Clear:Boolean;
begin
  if GrabEvent then
  try
    FillChar(FMemory^[0],FSize,0);
    FPosition:=0;
    Result:=True;
  finally ReleaseEvent end else Result:=False;
end;

function TMapStream.CopyFrom(AStream:TStream;Count:Integer):Boolean;

  function SizeGood:Boolean;
  var i,ASize:Integer;
  begin
    ASize:=AStream.Size;
    if (Count = 0) or (Count > ASize) then
    begin
      Count:=ASize;
      AStream.Position:=0;
    end;
    Result:=(FPosition + Count < FSize);
    {make sure the copy block is not too big. Incidentally, also make Count = 0
     as in Delphi.TStream}
  end;

begin
  if SizeGood and GrabEvent then
  try
    AStream.ReadBuffer(Byte(FMemory^[FPosition]),Count);
    Result:=True;
  finally ReleaseEvent end else Result:=False;
end;

function TMapStream.ReadBuffer(P:Pointer;Count:Integer):Boolean;
begin
  if CountGood(Count) and GrabEvent then
  try
    Move(FMemory^[FPosition],P^,Count);
    inc(FPosition,Count);
    Result:=True;
  finally ReleaseEvent end else Result:=False;
end;

function TMapStream.WriteBuffer(P:Pointer;Count:Integer):Boolean;
begin
  if CountGood(Count) and GrabEvent then
  try
    Move(P^,FMemory^[FPosition],Count);
    inc(FPosition,Count);
    Result:=True;
  finally ReleaseEvent end else Result:=False;
end;

procedure TMapStream.SetPosition(Value:Integer);
begin
  if (Value < FSize) and (Value >= 0) then FPosition:=Value;
end;

end.