]> git.saurik.com Git - apt.git/blob - apt-pkg/tagfile.cc
Fail over
[apt.git] / apt-pkg / tagfile.cc
1 // -*- mode: cpp; mode: fold -*-
2 // Description /*{{{*/
3 // $Id: tagfile.cc,v 1.18 1998/12/08 05:24:41 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
21 #include <string>
22 #include <stdio.h>
23 /*}}}*/
24
25 // TagFile::pkgTagFile - Constructor /*{{{*/
26 // ---------------------------------------------------------------------
27 /* */
28 pkgTagFile::pkgTagFile(FileFd &Fd,unsigned long Size) : Fd(Fd), Size(Size)
29 {
30 Buffer = new char[Size];
31 Start = End = Buffer;
32 Left = Fd.Size();
33 iOffset = 0;
34 Fill();
35 }
36 /*}}}*/
37 // TagFile::Step - Advance to the next section /*{{{*/
38 // ---------------------------------------------------------------------
39 /* If the Section Scanner fails we refill the buffer and try again. */
40 bool pkgTagFile::Step(pkgTagSection &Tag)
41 {
42 if (Tag.Scan(Start,End - Start) == false)
43 {
44 if (Fill() == false)
45 return false;
46
47 if (Tag.Scan(Start,End - Start) == false)
48 return _error->Error("Unable to parse package file %s",Fd.Name().c_str());
49 }
50 Start += Tag.size();
51 iOffset += Tag.size();
52
53 return true;
54 }
55 /*}}}*/
56 // TagFile::Fill - Top up the buffer /*{{{*/
57 // ---------------------------------------------------------------------
58 /* This takes the bit at the end of the buffer and puts it at the start
59 then fills the rest from the file */
60 bool pkgTagFile::Fill()
61 {
62 unsigned long EndSize = End - Start;
63
64 memmove(Buffer,Start,EndSize);
65 Start = Buffer;
66 End = Buffer + EndSize;
67
68 if (Left == 0)
69 {
70 if (EndSize <= 3)
71 return false;
72 if (Size - (End - Buffer) < 4)
73 return true;
74
75 // Append a double new line if one does not exist
76 unsigned int LineCount = 0;
77 for (const char *E = End - 1; E - End < 6 && (*E == '\n' || *E == '\r'); E--)
78 if (*E == '\n')
79 LineCount++;
80 for (; LineCount < 2; LineCount++)
81 *End++ = '\n';
82
83 return true;
84 }
85
86 // See if only a bit of the file is left
87 if (Left < Size - (End - Buffer))
88 {
89 if (Fd.Read(End,Left) == false)
90 return false;
91
92 End += Left;
93 Left = 0;
94 }
95 else
96 {
97 if (Fd.Read(End,Size - (End - Buffer)) == false)
98 return false;
99
100 Left -= Size - (End - Buffer);
101 End = Buffer + Size;
102 }
103 return true;
104 }
105 /*}}}*/
106 // TagFile::Jump - Jump to a pre-recorded location in the file /*{{{*/
107 // ---------------------------------------------------------------------
108 /* This jumps to a pre-recorded file location and reads the record
109 that is there */
110 bool pkgTagFile::Jump(pkgTagSection &Tag,unsigned long Offset)
111 {
112 iOffset = Offset;
113 Left = Fd.Size() - Offset;
114 if (Fd.Seek(Offset) == false)
115 return false;
116 End = Start = Buffer;
117
118 if (Fill() == false)
119 return false;
120
121 if (Tag.Scan(Start,End - Start) == false)
122 return _error->Error("Unable to parse package file");
123 return true;
124 }
125 /*}}}*/
126 // TagSection::Scan - Scan for the end of the header information /*{{{*/
127 // ---------------------------------------------------------------------
128 /* This looks for the first double new line in the data stream. It also
129 indexes the tags in the section. This very simple hash function for the
130 first 3 letters gives very good performance on the debian package files */
131 bool pkgTagSection::Scan(const char *Start,unsigned long MaxLength)
132 {
133 const char *End = Start + MaxLength;
134 Stop = Section = Start;
135 memset(AlphaIndexes,0,sizeof(AlphaIndexes));
136
137 if (Stop == 0)
138 return false;
139
140 TagCount = 0;
141 while (TagCount < sizeof(Indexes)/sizeof(Indexes[0]))
142 {
143 if (isspace(Stop[0]) == 0)
144 {
145 Indexes[TagCount++] = Stop - Section;
146 unsigned char A = tolower(Stop[0]) - 'a';
147 unsigned char B = tolower(Stop[1]) - 'a';
148 unsigned char C = tolower(Stop[3]) - 'a';
149 AlphaIndexes[((A + C/3)%26) + 26*((B + C/2)%26)] = TagCount;
150 }
151
152 Stop = (const char *)memchr(Stop,'\n',End - Stop);
153
154 if (Stop == 0)
155 return false;
156 for (; Stop[1] == '\r' && Stop < End; Stop++);
157
158 if (Stop[1] == '\n')
159 {
160 Indexes[TagCount] = Stop - Section;
161 for (; (Stop[0] == '\n' || Stop[0] == '\r') && Stop < End; Stop++);
162 return true;
163 }
164
165 Stop++;
166 }
167
168 return false;
169 }
170 /*}}}*/
171 // TagSection::Find - Locate a tag /*{{{*/
172 // ---------------------------------------------------------------------
173 /* This searches the section for a tag that matches the given string. */
174 bool pkgTagSection::Find(const char *Tag,const char *&Start,
175 const char *&End)
176 {
177 unsigned int Length = strlen(Tag);
178 unsigned char A = tolower(Tag[0]) - 'a';
179 unsigned char B = tolower(Tag[1]) - 'a';
180 unsigned char C = tolower(Tag[3]) - 'a';
181 unsigned int I = AlphaIndexes[((A + C/3)%26) + 26*((B + C/2)%26)];
182 if (I == 0)
183 return false;
184 I--;
185
186 for (unsigned int Counter = 0; Counter != TagCount; Counter++,
187 I = (I+1)%TagCount)
188 {
189 const char *St;
190 St = Section + Indexes[I];
191 if (strncasecmp(Tag,St,Length) != 0)
192 continue;
193
194 // Make sure the colon is in the right place
195 const char *C = St + Length;
196 for (; isspace(*C) != 0; C++);
197 if (*C != ':')
198 continue;
199
200 // Strip off the gunk from the start end
201 Start = C;
202 End = Section + Indexes[I+1];
203 for (; (isspace(*Start) != 0 || *Start == ':') && Start < End; Start++);
204 for (; isspace(End[-1]) != 0 && End > Start; End--);
205
206 return true;
207 }
208
209 Start = End = 0;
210 return false;
211 }
212 /*}}}*/
213 // TagSection::FindS - Find a string /*{{{*/
214 // ---------------------------------------------------------------------
215 /* */
216 string pkgTagSection::FindS(const char *Tag)
217 {
218 const char *Start;
219 const char *End;
220 if (Find(Tag,Start,End) == false)
221 return string();
222 return string(Start,End);
223 }
224 /*}}}*/
225 // TagSection::FindI - Find an integer /*{{{*/
226 // ---------------------------------------------------------------------
227 /* */
228 unsigned int pkgTagSection::FindI(const char *Tag)
229 {
230 const char *Start;
231 const char *End;
232 if (Find(Tag,Start,End) == false)
233 return 0;
234
235 return atoi(string(Start,End).c_str());
236 }
237 /*}}}*/
238