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