More MD5
[ntk/apt.git] / apt-pkg / tagfile.cc
CommitLineData
578bfd0a
AL
1// -*- mode: cpp; mode: fold -*-
2// Description /*{{{*/
29f7b36c 3// $Id: tagfile.cc,v 1.25 1999/07/03 06:45:40 jgg Exp $
578bfd0a
AL
4/* ######################################################################
5
6 Fast scanner for RFC-822 type header information
7
ad00ae81 8 This uses a rotating buffer to load the package information into.
578bfd0a
AL
9 The scanner runs over it and isolates and indexes a single section.
10
11 ##################################################################### */
12 /*}}}*/
13// Include Files /*{{{*/
6c139d6e 14#ifdef __GNUG__
094a497d 15#pragma implementation "apt-pkg/tagfile.h"
6c139d6e
AL
16#endif
17
094a497d
AL
18#include <apt-pkg/tagfile.h>
19#include <apt-pkg/error.h>
cdcc6d34 20#include <apt-pkg/strutl.h>
578bfd0a
AL
21
22#include <string>
23#include <stdio.h>
24 /*}}}*/
25
26// TagFile::pkgTagFile - Constructor /*{{{*/
27// ---------------------------------------------------------------------
28/* */
8e06abb2 29pkgTagFile::pkgTagFile(FileFd &Fd,unsigned long Size) : Fd(Fd), Size(Size)
578bfd0a 30{
ad00ae81
AL
31 Buffer = new char[Size];
32 Start = End = Buffer;
578bfd0a 33 Left = Fd.Size();
dcb79bae 34 iOffset = 0;
578bfd0a
AL
35 Fill();
36}
37 /*}}}*/
29f7b36c
AL
38// pkgTagFile::~pkgTagFile - Destructor /*{{{*/
39// ---------------------------------------------------------------------
40/* */
41pkgTagFile::~pkgTagFile()
42{
43 delete [] Buffer;
44}
45 /*}}}*/
578bfd0a
AL
46// TagFile::Step - Advance to the next section /*{{{*/
47// ---------------------------------------------------------------------
48/* If the Section Scanner fails we refill the buffer and try again. */
49bool pkgTagFile::Step(pkgTagSection &Tag)
50{
51 if (Tag.Scan(Start,End - Start) == false)
52 {
53 if (Fill() == false)
54 return false;
55
56 if (Tag.Scan(Start,End - Start) == false)
138d4b3d 57 return _error->Error("Unable to parse package file %s (1)",Fd.Name().c_str());
578bfd0a 58 }
dcb79bae
AL
59 Start += Tag.size();
60 iOffset += Tag.size();
61
578bfd0a
AL
62 return true;
63}
64 /*}}}*/
65// TagFile::Fill - Top up the buffer /*{{{*/
66// ---------------------------------------------------------------------
67/* This takes the bit at the end of the buffer and puts it at the start
68 then fills the rest from the file */
69bool pkgTagFile::Fill()
70{
ad00ae81 71 unsigned long EndSize = End - Start;
578bfd0a 72
c7b5ce1c
AL
73 memmove(Buffer,Start,EndSize);
74 Start = Buffer;
75 End = Buffer + EndSize;
76
578bfd0a
AL
77 if (Left == 0)
78 {
c7b5ce1c 79 if (EndSize <= 3)
578bfd0a 80 return false;
c7b5ce1c
AL
81 if (Size - (End - Buffer) < 4)
82 return true;
83
84 // Append a double new line if one does not exist
85 unsigned int LineCount = 0;
86 for (const char *E = End - 1; E - End < 6 && (*E == '\n' || *E == '\r'); E--)
87 if (*E == '\n')
88 LineCount++;
89 for (; LineCount < 2; LineCount++)
90 *End++ = '\n';
91
578bfd0a
AL
92 return true;
93 }
94
c88edf1d
AL
95 // See if only a bit of the file is left
96 if (Left < Size - (End - Buffer))
578bfd0a 97 {
ad00ae81 98 if (Fd.Read(End,Left) == false)
578bfd0a 99 return false;
c88edf1d 100
ad00ae81 101 End += Left;
578bfd0a
AL
102 Left = 0;
103 }
104 else
105 {
ad00ae81 106 if (Fd.Read(End,Size - (End - Buffer)) == false)
578bfd0a 107 return false;
c88edf1d 108
ad00ae81
AL
109 Left -= Size - (End - Buffer);
110 End = Buffer + Size;
578bfd0a
AL
111 }
112 return true;
113}
114 /*}}}*/
ad00ae81
AL
115// TagFile::Jump - Jump to a pre-recorded location in the file /*{{{*/
116// ---------------------------------------------------------------------
03e39e59
AL
117/* This jumps to a pre-recorded file location and reads the record
118 that is there */
ad00ae81
AL
119bool pkgTagFile::Jump(pkgTagSection &Tag,unsigned long Offset)
120{
121 iOffset = Offset;
122 Left = Fd.Size() - Offset;
123 if (Fd.Seek(Offset) == false)
124 return false;
125 End = Start = Buffer;
126
138d4b3d
AL
127 if (Fill() == false)
128 return false;
129
130 if (Tag.Scan(Start,End - Start) == true)
131 return true;
132
133 // This appends a double new line (for the real eof handling)
ad00ae81
AL
134 if (Fill() == false)
135 return false;
136
137 if (Tag.Scan(Start,End - Start) == false)
06bba740
AL
138 {
139 cout << string(Start,End) << endl;
138d4b3d 140 return _error->Error("Unable to parse package file %s (2)",Fd.Name().c_str());
06bba740
AL
141 }
142
ad00ae81
AL
143 return true;
144}
145 /*}}}*/
578bfd0a
AL
146// TagSection::Scan - Scan for the end of the header information /*{{{*/
147// ---------------------------------------------------------------------
148/* This looks for the first double new line in the data stream. It also
c1a22377
AL
149 indexes the tags in the section. This very simple hash function for the
150 first 3 letters gives very good performance on the debian package files */
578bfd0a
AL
151bool pkgTagSection::Scan(const char *Start,unsigned long MaxLength)
152{
153 const char *End = Start + MaxLength;
154 Stop = Section = Start;
c1a22377 155 memset(AlphaIndexes,0,sizeof(AlphaIndexes));
c7b5ce1c
AL
156
157 if (Stop == 0)
158 return false;
578bfd0a
AL
159
160 TagCount = 0;
f3bcc383 161 while (TagCount < sizeof(Indexes)/sizeof(Indexes[0]) && Stop < End)
578bfd0a 162 {
90d64280 163 // Start a new index and add it to the hash
c1a22377
AL
164 if (isspace(Stop[0]) == 0)
165 {
166 Indexes[TagCount++] = Stop - Section;
167 unsigned char A = tolower(Stop[0]) - 'a';
168 unsigned char B = tolower(Stop[1]) - 'a';
169 unsigned char C = tolower(Stop[3]) - 'a';
170 AlphaIndexes[((A + C/3)%26) + 26*((B + C/2)%26)] = TagCount;
171 }
0a8e3465 172
c1a22377 173 Stop = (const char *)memchr(Stop,'\n',End - Stop);
0a8e3465 174
c1a22377
AL
175 if (Stop == 0)
176 return false;
138d4b3d 177
90d64280 178 for (; Stop[1] == '\r' && Stop+1 < End; Stop++);
c1a22377 179
f3bcc383
AL
180 // Double newline marks the end of the record
181 if (Stop+1 < End && Stop[1] == '\n')
578bfd0a 182 {
578bfd0a 183 Indexes[TagCount] = Stop - Section;
0a8e3465 184 for (; (Stop[0] == '\n' || Stop[0] == '\r') && Stop < End; Stop++);
578bfd0a 185 return true;
578bfd0a
AL
186 }
187
c1a22377
AL
188 Stop++;
189 }
138d4b3d 190
578bfd0a
AL
191 return false;
192}
193 /*}}}*/
194// TagSection::Find - Locate a tag /*{{{*/
195// ---------------------------------------------------------------------
196/* This searches the section for a tag that matches the given string. */
197bool pkgTagSection::Find(const char *Tag,const char *&Start,
198 const char *&End)
199{
200 unsigned int Length = strlen(Tag);
c1a22377
AL
201 unsigned char A = tolower(Tag[0]) - 'a';
202 unsigned char B = tolower(Tag[1]) - 'a';
203 unsigned char C = tolower(Tag[3]) - 'a';
204 unsigned int I = AlphaIndexes[((A + C/3)%26) + 26*((B + C/2)%26)];
205 if (I == 0)
206 return false;
207 I--;
208
209 for (unsigned int Counter = 0; Counter != TagCount; Counter++,
210 I = (I+1)%TagCount)
578bfd0a 211 {
c1a22377
AL
212 const char *St;
213 St = Section + Indexes[I];
214 if (strncasecmp(Tag,St,Length) != 0)
578bfd0a
AL
215 continue;
216
217 // Make sure the colon is in the right place
c1a22377 218 const char *C = St + Length;
578bfd0a
AL
219 for (; isspace(*C) != 0; C++);
220 if (*C != ':')
221 continue;
222
223 // Strip off the gunk from the start end
224 Start = C;
225 End = Section + Indexes[I+1];
06bba740
AL
226 if (Start >= End)
227 return _error->Error("Internal parsing error");
228
578bfd0a
AL
229 for (; (isspace(*Start) != 0 || *Start == ':') && Start < End; Start++);
230 for (; isspace(End[-1]) != 0 && End > Start; End--);
06bba740 231
578bfd0a
AL
232 return true;
233 }
c1a22377 234
578bfd0a
AL
235 Start = End = 0;
236 return false;
237}
238 /*}}}*/
0e66b144 239// TagSection::FindS - Find a string /*{{{*/
a05599f1
AL
240// ---------------------------------------------------------------------
241/* */
242string pkgTagSection::FindS(const char *Tag)
243{
244 const char *Start;
245 const char *End;
246 if (Find(Tag,Start,End) == false)
247 return string();
248 return string(Start,End);
249}
250 /*}}}*/
251// TagSection::FindI - Find an integer /*{{{*/
252// ---------------------------------------------------------------------
253/* */
b0b4efb9 254signed int pkgTagSection::FindI(const char *Tag,signed long Default)
a05599f1
AL
255{
256 const char *Start;
b0b4efb9
AL
257 const char *Stop;
258 if (Find(Tag,Start,Stop) == false)
259 return Default;
260
261 // Copy it into a temp buffer so we can use strtol
262 char S[300];
263 if ((unsigned)(Stop - Start) >= sizeof(S))
264 return Default;
265 strncpy(S,Start,Stop-Start);
266 S[Stop - Start] = 0;
267
268 char *End;
269 signed long Result = strtol(S,&End,10);
270 if (S == End)
271 return Default;
272 return Result;
273}
274 /*}}}*/
275// TagSection::FindFlag - Locate a yes/no type flag /*{{{*/
276// ---------------------------------------------------------------------
277/* The bits marked in Flag are masked on/off in Flags */
278bool pkgTagSection::FindFlag(const char *Tag,unsigned long &Flags,
279 unsigned long Flag)
280{
281 const char *Start;
282 const char *Stop;
283 if (Find(Tag,Start,Stop) == false)
284 return true;
a05599f1 285
b0b4efb9
AL
286 switch (StringToBool(string(Start,Stop)))
287 {
288 case 0:
289 Flags &= ~Flag;
290 return true;
291
292 case 1:
293 Flags |= Flag;
294 return true;
295
296 default:
297 _error->Warning("Unknown flag value");
298 return true;
299 }
300 return true;
a05599f1
AL
301}
302 /*}}}*/