protected function process_report_data($data, $report_password)
 {
     if (strlen($data) == 0) {
         $this->log->add("ERR_NO_REPORT_DATA");
         return false;
     } else {
         if (strlen($data) < 12) {
             $this->log->add("ERR_INVALID_REPORT_DATALEN");
             return false;
         } else {
             if (strlen($data) > REPORT_LEN_LIMIT) {
                 $this->log->add("ERR_CANNOT_PROCESS_REPORT_MEMLIMIT");
                 return false;
             } elseif (strlen($data) == 12) {
                 // empty report
                 return true;
             }
         }
     }
     // extract crc32 checksum from datastream
     $crc_chk = data_int32(substr($data, strlen($data) - 4));
     // remove crc32 checksum from the data stream
     $data = substr($data, 0, -4);
     // check report validness
     $crc_chk = obf_crc32($crc_chk);
     if ((int) crc32($data) != (int) $crc_chk) {
         $this->log->add("ERR_REPORT_CRC_MISMATCH");
         return false;
     }
     $stream = new stream($data, $this->log);
     $report_id = $stream->read_strlen(8);
     if ($report_id == REPORT_CRYPTED_HEADER && $stream->state) {
         $decrypted_data = rc4Decrypt($report_password, substr($data, 8));
         // there's another crc32 checksum available to verify the decryption process
         // extract crc32 checksum from decrypted datastream
         $crc_chk = data_int32(substr($decrypted_data, strlen($decrypted_data) - 4));
         // remove crc32 checksum from the data stream
         $decrypted_data = substr($decrypted_data, 0, -4);
         // check report validness
         $crc_chk = obf_crc32($crc_chk);
         if ((int) crc32($decrypted_data) != (int) $crc_chk) {
             $this->log->add("ERR_REPORT_WRONG_PASSWORD");
             return false;
         }
         // update current stream with decrypted data
         $stream = new stream($decrypted_data, $this->log);
         $report_id = $stream->read_strlen(8);
     }
     if ($report_id == REPORT_PACKED_HEADER && $stream->state) {
         // unpack stream data
         $unpacked_len = $stream->read_dword();
         $packed_data = $stream->read_str();
         if ($unpacked_len > REPORT_LEN_LIMIT || strlen($packed_data) > REPORT_LEN_LIMIT) {
             $this->log->add("ERR_UNPACK_LEN_LIMIT");
             return false;
         }
         if (!strlen($packed_data)) {
             $this->log->add("ERR_UNPACK_NULL");
             return false;
         }
         $unpacked_data = "";
         if ($stream->state && strlen($packed_data)) {
             $unpacked_data = $this->unpack_stream($packed_data, $unpacked_len);
         }
         if (!strlen($unpacked_data)) {
             $this->log->add("ERR_UNPACK_FAIL");
             return false;
         }
         if (strlen($unpacked_data) > REPORT_LEN_LIMIT) {
             $this->log->add("ERR_UNPACK_LEN_LIMIT");
             return false;
         }
         $stream = new stream($unpacked_data, $this->log);
         $report_id = $stream->read_strlen(8);
     }
     if ($report_id != REPORT_HEADER || !$stream->state) {
         $this->log->add("ERR_INVALID_REPORT_HEADER");
         return false;
     }
     $version_id = ztrim($stream->read_strlen(8));
     if (!$stream->state) {
         $this->log->add("ERR_CANNOT_READ_VERSION_ID");
         return false;
     }
     if ($version_id != REPORT_VERSION) {
         $this->log->add("ERR_INVALID_VERSION_ID");
         return false;
     }
     $this->report_version_id = $version_id;
     while ($stream->state && $stream->pos < $stream->datalen) {
         if (!$this->import_module($stream, $this->log)) {
             $this->log->add("ERR_CANNOT_IMPORT_MODULE");
             return false;
         }
     }
     return $stream->pos == $stream->datalen && $stream->state;
 }