Upstream version 5.34.98.0
[platform/framework/web/crosswalk.git] / src / net / base / gzip_header.cc
1 // Copyright (c) 2011 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "net/base/gzip_header.h"
6
7 #include <algorithm>
8
9 #include "base/logging.h"
10 #include "third_party/zlib/zlib.h"
11
12 namespace net {
13
14 const uint8 GZipHeader::magic[] = { 0x1f, 0x8b };
15
16 GZipHeader::GZipHeader() {
17   Reset();
18 }
19
20 GZipHeader::~GZipHeader() {
21 }
22
23 void GZipHeader::Reset() {
24   state_        = IN_HEADER_ID1;
25   flags_        = 0;
26   extra_length_ = 0;
27 }
28
29 GZipHeader::Status GZipHeader::ReadMore(const char* inbuf, int inbuf_len,
30                                         const char** header_end) {
31   DCHECK_GE(inbuf_len, 0);
32   const uint8* pos = reinterpret_cast<const uint8*>(inbuf);
33   const uint8* const end = pos + inbuf_len;
34
35   while ( pos < end ) {
36     switch ( state_ ) {
37       case IN_HEADER_ID1:
38         if ( *pos != magic[0] )  return INVALID_HEADER;
39         pos++;
40         state_++;
41         break;
42       case IN_HEADER_ID2:
43         if ( *pos != magic[1] )  return INVALID_HEADER;
44         pos++;
45         state_++;
46         break;
47       case IN_HEADER_CM:
48         if ( *pos != Z_DEFLATED )  return INVALID_HEADER;
49         pos++;
50         state_++;
51         break;
52       case IN_HEADER_FLG:
53         flags_ = (*pos) & (FLAG_FHCRC | FLAG_FEXTRA |
54                            FLAG_FNAME | FLAG_FCOMMENT);
55         pos++;
56         state_++;
57         break;
58
59       case IN_HEADER_MTIME_BYTE_0:
60         pos++;
61         state_++;
62         break;
63       case IN_HEADER_MTIME_BYTE_1:
64         pos++;
65         state_++;
66         break;
67       case IN_HEADER_MTIME_BYTE_2:
68         pos++;
69         state_++;
70         break;
71       case IN_HEADER_MTIME_BYTE_3:
72         pos++;
73         state_++;
74         break;
75
76       case IN_HEADER_XFL:
77         pos++;
78         state_++;
79         break;
80
81       case IN_HEADER_OS:
82         pos++;
83         state_++;
84         break;
85
86       case IN_XLEN_BYTE_0:
87         if ( !(flags_ & FLAG_FEXTRA) ) {
88           state_ = IN_FNAME;
89           break;
90         }
91         // We have a two-byte little-endian length, followed by a
92         // field of that length.
93         extra_length_ = *pos;
94         pos++;
95         state_++;
96         break;
97       case IN_XLEN_BYTE_1:
98         extra_length_ += *pos << 8;
99         pos++;
100         state_++;
101         // We intentionally fall through, because if we have a
102         // zero-length FEXTRA, we want to check to notice that we're
103         // done reading the FEXTRA before we exit this loop...
104
105       case IN_FEXTRA: {
106         // Grab the rest of the bytes in the extra field, or as many
107         // of them as are actually present so far.
108         const int num_extra_bytes = static_cast<const int>(std::min(
109             static_cast<ptrdiff_t>(extra_length_),
110             (end - pos)));
111         pos += num_extra_bytes;
112         extra_length_ -= num_extra_bytes;
113         if ( extra_length_ == 0 ) {
114           state_ = IN_FNAME;   // advance when we've seen extra_length_ bytes
115           flags_ &= ~FLAG_FEXTRA;   // we're done with the FEXTRA stuff
116         }
117         break;
118       }
119
120       case IN_FNAME:
121         if ( !(flags_ & FLAG_FNAME) ) {
122           state_ = IN_FCOMMENT;
123           break;
124         }
125         // See if we can find the end of the \0-terminated FNAME field.
126         pos = reinterpret_cast<const uint8*>(memchr(pos, '\0', (end - pos)));
127         if ( pos != NULL ) {
128           pos++;  // advance past the '\0'
129           flags_ &= ~FLAG_FNAME;   // we're done with the FNAME stuff
130           state_ = IN_FCOMMENT;
131         } else {
132           pos = end;  // everything we have so far is part of the FNAME
133         }
134         break;
135
136       case IN_FCOMMENT:
137         if ( !(flags_ & FLAG_FCOMMENT) ) {
138           state_ = IN_FHCRC_BYTE_0;
139           break;
140         }
141         // See if we can find the end of the \0-terminated FCOMMENT field.
142         pos = reinterpret_cast<const uint8*>(memchr(pos, '\0', (end - pos)));
143         if ( pos != NULL ) {
144           pos++;  // advance past the '\0'
145           flags_ &= ~FLAG_FCOMMENT;   // we're done with the FCOMMENT stuff
146           state_ = IN_FHCRC_BYTE_0;
147         } else {
148           pos = end;  // everything we have so far is part of the FNAME
149         }
150         break;
151
152       case IN_FHCRC_BYTE_0:
153         if ( !(flags_ & FLAG_FHCRC) ) {
154           state_ = IN_DONE;
155           break;
156         }
157         pos++;
158         state_++;
159         break;
160
161       case IN_FHCRC_BYTE_1:
162         pos++;
163         flags_ &= ~FLAG_FHCRC;   // we're done with the FHCRC stuff
164         state_++;
165         break;
166
167       case IN_DONE:
168         *header_end = reinterpret_cast<const char*>(pos);
169         return COMPLETE_HEADER;
170     }
171   }
172
173   if ( (state_ > IN_HEADER_OS) && (flags_ == 0) ) {
174     *header_end = reinterpret_cast<const char*>(pos);
175     return COMPLETE_HEADER;
176   } else {
177     return INCOMPLETE_HEADER;
178   }
179 }
180
181 }  // namespace net