Spaces:
Sleeping
Sleeping
| // Copyright 2002 Google LLC | |
| // | |
| // Licensed under the Apache License, Version 2.0 (the "License"); | |
| // you may not use this file except in compliance with the License. | |
| // You may obtain a copy of the License at | |
| // | |
| // http://www.apache.org/licenses/LICENSE-2.0 | |
| // | |
| // Unless required by applicable law or agreed to in writing, software | |
| // distributed under the License is distributed on an "AS IS" BASIS, | |
| // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
| // See the License for the specific language governing permissions and | |
| // limitations under the License. | |
| // | |
| // Author: Neal Cardwell | |
| // | |
| namespace csrblocksparse { | |
| const uint8_t GZipHeader::magic[] = {0x1f, 0x8b}; | |
| // ---------------------------------------------------------------------- | |
| // GZipHeader::ReadMore() | |
| // Attempt to parse the beginning of the given buffer as a gzip | |
| // header. If these bytes do not constitute a complete gzip header, | |
| // return INCOMPLETE_HEADER. If these bytes do not constitute a | |
| // *valid* gzip header, return INVALID_HEADER. If we find a | |
| // complete header, return COMPLETE_HEADER and set the pointer | |
| // pointed to by header_end to the first byte beyond the gzip header. | |
| // ---------------------------------------------------------------------- | |
| GZipHeader::Status GZipHeader::ReadMore(const char* inbuf, int inbuf_len, | |
| const char** header_end) { | |
| CHECK_GE(inbuf_len, 0); | |
| const uint8_t* pos = reinterpret_cast<const uint8_t*>(inbuf); | |
| const uint8_t* const end = pos + inbuf_len; | |
| while (pos < end) { | |
| switch (state_) { | |
| case IN_HEADER_ID1: | |
| if (*pos != magic[0]) return INVALID_HEADER; | |
| pos++; | |
| state_++; | |
| break; | |
| case IN_HEADER_ID2: | |
| if (*pos != magic[1]) return INVALID_HEADER; | |
| pos++; | |
| state_++; | |
| break; | |
| case IN_HEADER_CM: | |
| if (*pos != Z_DEFLATED) return INVALID_HEADER; | |
| pos++; | |
| state_++; | |
| break; | |
| case IN_HEADER_FLG: | |
| flags_ = | |
| (*pos) & (FLAG_FHCRC | FLAG_FEXTRA | FLAG_FNAME | FLAG_FCOMMENT); | |
| pos++; | |
| state_++; | |
| break; | |
| case IN_HEADER_MTIME_BYTE_0: | |
| pos++; | |
| state_++; | |
| break; | |
| case IN_HEADER_MTIME_BYTE_1: | |
| pos++; | |
| state_++; | |
| break; | |
| case IN_HEADER_MTIME_BYTE_2: | |
| pos++; | |
| state_++; | |
| break; | |
| case IN_HEADER_MTIME_BYTE_3: | |
| pos++; | |
| state_++; | |
| break; | |
| case IN_HEADER_XFL: | |
| pos++; | |
| state_++; | |
| break; | |
| case IN_HEADER_OS: | |
| pos++; | |
| state_++; | |
| break; | |
| case IN_XLEN_BYTE_0: | |
| if (!(flags_ & FLAG_FEXTRA)) { | |
| state_ = IN_FNAME; | |
| break; | |
| } | |
| // We have a two-byte little-endian length, followed by a | |
| // field of that length. | |
| extra_length_ = *pos; | |
| pos++; | |
| state_++; | |
| break; | |
| case IN_XLEN_BYTE_1: | |
| extra_length_ += *pos << 8; | |
| pos++; | |
| state_++; | |
| // If we have a zero-length FEXTRA, we want to check to notice that | |
| // we're done reading the FEXTRA before we exit this loop... | |
| ABSL_FALLTHROUGH_INTENDED; | |
| case IN_FEXTRA: { | |
| // Grab the rest of the bytes in the extra field, or as many | |
| // of them as are actually present so far. | |
| const int num_extra_bytes = std::min<int>(extra_length_, (end - pos)); | |
| pos += num_extra_bytes; | |
| extra_length_ -= num_extra_bytes; | |
| if (extra_length_ == 0) { | |
| state_ = IN_FNAME; // advance when we've seen extra_length_ bytes | |
| flags_ &= ~FLAG_FEXTRA; // we're done with the FEXTRA stuff | |
| } | |
| break; | |
| } | |
| case IN_FNAME: | |
| if (!(flags_ & FLAG_FNAME)) { | |
| state_ = IN_FCOMMENT; | |
| break; | |
| } | |
| // See if we can find the end of the \0-terminated FNAME field. | |
| pos = reinterpret_cast<const uint8_t*>(memchr(pos, '\0', (end - pos))); | |
| if (pos != nullptr) { | |
| pos++; // advance past the '\0' | |
| flags_ &= ~FLAG_FNAME; // we're done with the FNAME stuff | |
| state_ = IN_FCOMMENT; | |
| } else { | |
| pos = end; // everything we have so far is part of the FNAME | |
| } | |
| break; | |
| case IN_FCOMMENT: | |
| if (!(flags_ & FLAG_FCOMMENT)) { | |
| state_ = IN_FHCRC_BYTE_0; | |
| break; | |
| } | |
| // See if we can find the end of the \0-terminated FCOMMENT field. | |
| pos = reinterpret_cast<const uint8_t*>(memchr(pos, '\0', (end - pos))); | |
| if (pos != nullptr) { | |
| pos++; // advance past the '\0' | |
| flags_ &= ~FLAG_FCOMMENT; // we're done with the FCOMMENT stuff | |
| state_ = IN_FHCRC_BYTE_0; | |
| } else { | |
| pos = end; // everything we have so far is part of the FNAME | |
| } | |
| break; | |
| case IN_FHCRC_BYTE_0: | |
| if (!(flags_ & FLAG_FHCRC)) { | |
| state_ = IN_DONE; | |
| break; | |
| } | |
| pos++; | |
| state_++; | |
| break; | |
| case IN_FHCRC_BYTE_1: | |
| pos++; | |
| flags_ &= ~FLAG_FHCRC; // we're done with the FHCRC stuff | |
| state_++; | |
| break; | |
| case IN_DONE: | |
| *header_end = reinterpret_cast<const char*>(pos); | |
| return COMPLETE_HEADER; | |
| } | |
| } | |
| if ((state_ > IN_HEADER_OS) && (flags_ == 0)) { | |
| *header_end = reinterpret_cast<const char*>(pos); | |
| return COMPLETE_HEADER; | |
| } else { | |
| return INCOMPLETE_HEADER; | |
| } | |
| } | |
| } // namespace csrblocksparse | |