ByteVector ID3v2::Tag::render(int version) const { // We need to render the "tag data" first so that we have to correct size to // render in the tag's header. The "tag data" -- everything that is included // in ID3v2::Header::tagSize() -- includes the extended header, frames and // padding, but does not include the tag's header or footer. if(version != 3 && version != 4) { debug("Unknown ID3v2 version, using ID3v2.4"); version = 4; } // TODO: Render the extended header. // Downgrade the frames that ID3v2.3 doesn't support. FrameList newFrames; newFrames.setAutoDelete(true); FrameList frameList; if(version == 4) { frameList = d->frameList; } else { downgradeFrames(&frameList, &newFrames); } // Reserve a 10-byte blank space for an ID3v2 tag header. ByteVector tagData(Header::size(), '\0'); // Loop through the frames rendering them and adding them to the tagData. for(FrameList::ConstIterator it = frameList.begin(); it != frameList.end(); it++) { (*it)->header()->setVersion(version); if((*it)->header()->frameID().size() != 4) { debug("An ID3v2 frame of unsupported or unknown type \'" + String((*it)->header()->frameID()) + "\' has been discarded"); continue; } if(!(*it)->header()->tagAlterPreservation()) { const ByteVector frameData = (*it)->render(); if(frameData.size() == Frame::headerSize((*it)->header()->version())) { debug("An empty ID3v2 frame \'" + String((*it)->header()->frameID()) + "\' has been discarded"); continue; } tagData.append(frameData); } } // Compute the amount of padding, and append that to tagData. // TODO: Should be calculated in long long in taglib2. long originalSize = d->header.tagSize(); long paddingSize = originalSize - (tagData.size() - Header::size()); if(paddingSize <= 0) { paddingSize = MinPaddingSize; } else { // Padding won't increase beyond 1% of the file size or 1MB. long threshold = d->file ? d->file->length() / 100 : 0; threshold = std::max(threshold, MinPaddingSize); threshold = std::min(threshold, MaxPaddingSize); if(paddingSize > threshold) paddingSize = MinPaddingSize; } tagData.resize(static_cast<unsigned int>(tagData.size() + paddingSize), '\0'); // Set the version and data size. d->header.setMajorVersion(version); d->header.setTagSize(tagData.size() - Header::size()); // TODO: This should eventually include d->footer->render(). const ByteVector headerData = d->header.render(); std::copy(headerData.begin(), headerData.end(), tagData.begin()); return tagData; }
Frame *FrameFactory::createFrame(const ByteVector &data, uint version) const { Frame::Header *header = new Frame::Header(data, version); ByteVector frameID = header->frameID(); // A quick sanity check -- make sure that the frameID is 4 uppercase Latin1 // characters. Also make sure that there is data in the frame. if(!frameID.size() == (version < 3 ? 3 : 4) || header->frameSize() <= 0 || header->frameSize() > data.size()) { delete header; return 0; } for(ByteVector::ConstIterator it = frameID.begin(); it != frameID.end(); it++) { if( (*it < 'A' || *it > 'Z') && (*it < '1' || *it > '9') ) { delete header; return 0; } } // TagLib doesn't mess with encrypted frames, so just treat them // as unknown frames. #if HAVE_ZLIB == 0 if(header->compression()) { debug("Compressed frames are currently not supported."); return new UnknownFrame(data, header); } #endif if(header->encryption()) { debug("Encrypted frames are currently not supported."); return new UnknownFrame(data, header); } if(!updateFrame(header)) { header->setTagAlterPreservation(true); return new UnknownFrame(data, header); } // updateFrame() might have updated the frame ID. frameID = header->frameID(); // This is where things get necissarily nasty. Here we determine which // Frame subclass (or if none is found simply an Frame) based // on the frame ID. Since there are a lot of possibilities, that means // a lot of if blocks. // Text Identification (frames 4.2) if(frameID.startsWith("T")) { TextIdentificationFrame *f = frameID != "TXXX" ? new TextIdentificationFrame(data, header) : new UserTextIdentificationFrame(data, header); if(d->useDefaultEncoding) f->setTextEncoding(d->defaultEncoding); if(frameID == "TCON") updateGenre(f); return f; } // Comments (frames 4.10) if(frameID == "COMM") { CommentsFrame *f = new CommentsFrame(data, header); if(d->useDefaultEncoding) f->setTextEncoding(d->defaultEncoding); return f; } // Attached Picture (frames 4.14) if(frameID == "APIC") { AttachedPictureFrame *f = new AttachedPictureFrame(data, header); if(d->useDefaultEncoding) f->setTextEncoding(d->defaultEncoding); return f; } // Relative Volume Adjustment (frames 4.11) if(frameID == "RVA2") return new RelativeVolumeFrame(data, header); // Unique File Identifier (frames 4.1) if(frameID == "UFID") return new UniqueFileIdentifierFrame(data, header); // General Encapsulated Object (frames 4.15) if(frameID == "GEOB") return new GeneralEncapsulatedObjectFrame(data, header); return new UnknownFrame(data, header); }
Frame *FrameFactory::createFrame(const ByteVector &origData, Header *tagHeader) const { ByteVector data = origData; uint version = tagHeader->majorVersion(); Frame::Header *header = new Frame::Header(data, version); ByteVector frameID = header->frameID(); // A quick sanity check -- make sure that the frameID is 4 uppercase Latin1 // characters. Also make sure that there is data in the frame. if(!frameID.size() == (version < 3 ? 3 : 4) || header->frameSize() <= uint(header->dataLengthIndicator() ? 4 : 0) || header->frameSize() > data.size()) { delete header; return 0; } for(ByteVector::ConstIterator it = frameID.begin(); it != frameID.end(); it++) { if( (*it < 'A' || *it > 'Z') && (*it < '1' || *it > '9') ) { delete header; return 0; } } if(version > 3 && (tagHeader->unsynchronisation() || header->unsynchronisation())) { // Data lengths are not part of the encoded data, but since they are synch-safe // integers they will be never actually encoded. ByteVector frameData = data.mid(Frame::Header::size(version), header->frameSize()); frameData = SynchData::decode(frameData); data = data.mid(0, Frame::Header::size(version)) + frameData; } // TagLib doesn't mess with encrypted frames, so just treat them // as unknown frames. #if HAVE_ZLIB == 0 if(header->compression()) { debug("Compressed frames are currently not supported."); return new UnknownFrame(data, header); } #endif if(header->encryption()) { debug("Encrypted frames are currently not supported."); return new UnknownFrame(data, header); } if(!updateFrame(header)) { header->setTagAlterPreservation(true); return new UnknownFrame(data, header); } // updateFrame() might have updated the frame ID. frameID = header->frameID(); // This is where things get necissarily nasty. Here we determine which // Frame subclass (or if none is found simply an Frame) based // on the frame ID. Since there are a lot of possibilities, that means // a lot of if blocks. // Text Identification (frames 4.2) if(frameID.startsWith("T")) { TextIdentificationFrame *f = frameID != "TXXX" ? new TextIdentificationFrame(data, header) : new UserTextIdentificationFrame(data, header); d->setTextEncoding(f); if(frameID == "TCON") updateGenre(f); return f; } // Comments (frames 4.10) if(frameID == "COMM") { CommentsFrame *f = new CommentsFrame(data, header); d->setTextEncoding(f); return f; } // Attached Picture (frames 4.14) if(frameID == "APIC") { AttachedPictureFrame *f = new AttachedPictureFrame(data, header); d->setTextEncoding(f); return f; } // ID3v2.2 Attached Picture if(frameID == "PIC") { AttachedPictureFrame *f = new AttachedPictureFrameV22(data, header); d->setTextEncoding(f); return f; } // Relative Volume Adjustment (frames 4.11) if(frameID == "RVA2") return new RelativeVolumeFrame(data, header); // Unique File Identifier (frames 4.1) if(frameID == "UFID") return new UniqueFileIdentifierFrame(data, header); // General Encapsulated Object (frames 4.15) if(frameID == "GEOB") { GeneralEncapsulatedObjectFrame *f = new GeneralEncapsulatedObjectFrame(data, header); d->setTextEncoding(f); return f; } // URL link (frames 4.3) if(frameID.startsWith("W")) { if(frameID != "WXXX") { return new UrlLinkFrame(data, header); } else { UserUrlLinkFrame *f = new UserUrlLinkFrame(data, header); d->setTextEncoding(f); return f; } } // Unsynchronized lyric/text transcription (frames 4.8) if(frameID == "USLT") { UnsynchronizedLyricsFrame *f = new UnsynchronizedLyricsFrame(data, header); if(d->useDefaultEncoding) f->setTextEncoding(d->defaultEncoding); return f; } // Popularimeter (frames 4.17) if(frameID == "POPM") return new PopularimeterFrame(data, header); // Private (frames 4.27) if(frameID == "PRIV") return new PrivateFrame(data, header); return new UnknownFrame(data, header); }
Frame *FrameFactory::createFrame(const ByteVector &origData, const Header *tagHeader) const { ByteVector data = origData; unsigned int version = tagHeader->majorVersion(); Frame::Header *header = new Frame::Header(data, version); ByteVector frameID = header->frameID(); // A quick sanity check -- make sure that the frameID is 4 uppercase Latin1 // characters. Also make sure that there is data in the frame. if(frameID.size() != (version < 3 ? 3 : 4) || header->frameSize() <= static_cast<unsigned int>(header->dataLengthIndicator() ? 4 : 0) || header->frameSize() > data.size()) { delete header; return 0; } #ifndef NO_ITUNES_HACKS if(version == 3 && frameID.size() == 4 && frameID[3] == '\0') { // iTunes v2.3 tags store v2.2 frames - convert now frameID = frameID.mid(0, 3); header->setFrameID(frameID); header->setVersion(2); updateFrame(header); header->setVersion(3); } #endif for(ByteVector::ConstIterator it = frameID.begin(); it != frameID.end(); it++) { if( (*it < 'A' || *it > 'Z') && (*it < '0' || *it > '9') ) { delete header; return 0; } } if(version > 3 && (tagHeader->unsynchronisation() || header->unsynchronisation())) { // Data lengths are not part of the encoded data, but since they are synch-safe // integers they will be never actually encoded. ByteVector frameData = data.mid(Frame::Header::size(version), header->frameSize()); frameData = SynchData::decode(frameData); data = data.mid(0, Frame::Header::size(version)) + frameData; } // TagLib doesn't mess with encrypted frames, so just treat them // as unknown frames. #if !defined(HAVE_ZLIB) || HAVE_ZLIB == 0 if(header->compression()) { debug("Compressed frames are currently not supported."); return new UnknownFrame(data, header); } #endif if(header->encryption()) { debug("Encrypted frames are currently not supported."); return new UnknownFrame(data, header); } if(!updateFrame(header)) { header->setTagAlterPreservation(true); return new UnknownFrame(data, header); } // updateFrame() might have updated the frame ID. frameID = header->frameID(); // This is where things get necissarily nasty. Here we determine which // Frame subclass (or if none is found simply an Frame) based // on the frame ID. Since there are a lot of possibilities, that means // a lot of if blocks. // Text Identification (frames 4.2) // Apple proprietary WFED (Podcast URL) is in fact a text frame. if(frameID.startsWith("T") || frameID == "WFED") { TextIdentificationFrame *f = frameID != "TXXX" ? new TextIdentificationFrame(data, header) : new UserTextIdentificationFrame(data, header); d->setTextEncoding(f); if(frameID == "TCON") updateGenre(f); return f; } // Comments (frames 4.10) if(frameID == "COMM") { CommentsFrame *f = new CommentsFrame(data, header); d->setTextEncoding(f); return f; } // Attached Picture (frames 4.14) if(frameID == "APIC") { AttachedPictureFrame *f = new AttachedPictureFrame(data, header); d->setTextEncoding(f); return f; } // ID3v2.2 Attached Picture if(frameID == "PIC") { AttachedPictureFrame *f = new AttachedPictureFrameV22(data, header); d->setTextEncoding(f); return f; } // Relative Volume Adjustment (frames 4.11) if(frameID == "RVA2") return new RelativeVolumeFrame(data, header); // Unique File Identifier (frames 4.1) if(frameID == "UFID") return new UniqueFileIdentifierFrame(data, header); // General Encapsulated Object (frames 4.15) if(frameID == "GEOB") { GeneralEncapsulatedObjectFrame *f = new GeneralEncapsulatedObjectFrame(data, header); d->setTextEncoding(f); return f; } // URL link (frames 4.3) if(frameID.startsWith("W")) { if(frameID != "WXXX") { return new UrlLinkFrame(data, header); } else { UserUrlLinkFrame *f = new UserUrlLinkFrame(data, header); d->setTextEncoding(f); return f; } } // Unsynchronized lyric/text transcription (frames 4.8) if(frameID == "USLT") { UnsynchronizedLyricsFrame *f = new UnsynchronizedLyricsFrame(data, header); if(d->useDefaultEncoding) f->setTextEncoding(d->defaultEncoding); return f; } // Synchronised lyrics/text (frames 4.9) if(frameID == "SYLT") { SynchronizedLyricsFrame *f = new SynchronizedLyricsFrame(data, header); if(d->useDefaultEncoding) f->setTextEncoding(d->defaultEncoding); return f; } // Event timing codes (frames 4.5) if(frameID == "ETCO") return new EventTimingCodesFrame(data, header); // Popularimeter (frames 4.17) if(frameID == "POPM") return new PopularimeterFrame(data, header); // Private (frames 4.27) if(frameID == "PRIV") return new PrivateFrame(data, header); // Ownership (frames 4.22) if(frameID == "OWNE") { OwnershipFrame *f = new OwnershipFrame(data, header); d->setTextEncoding(f); return f; } // Chapter (ID3v2 chapters 1.0) if(frameID == "CHAP") return new ChapterFrame(tagHeader, data, header); // Table of contents (ID3v2 chapters 1.0) if(frameID == "CTOC") return new TableOfContentsFrame(tagHeader, data, header); // Apple proprietary PCST (Podcast) if(frameID == "PCST") return new PodcastFrame(data, header); return new UnknownFrame(data, header); }
bool CHttpServer::receive_request(ByteVector &request) { if (verbose) RAWTRACE("Receiving request..."); ByteVector r; char buf[BUF_SIZE]; for(;;) { if (verbose) RAWTRACE("Read portion of data from socket..."); int n = recv(m_sock, &buf[0], sizeof(buf), 0); if (n == -1) { int e = RHO_NET_ERROR_CODE; #if !defined(WINDOWS_PLATFORM) if (e == EINTR) continue; #else if (e == WSAEINTR) continue; #endif #if defined(OS_WP8) if (e == EAGAIN || e == WSAEWOULDBLOCK) { #else if (e == EAGAIN) { #endif if (!r.empty()) break; fd_set fds; FD_ZERO(&fds); FD_SET(m_sock, &fds); select(m_sock + 1, &fds, 0, 0, 0); continue; } RAWLOG_ERROR1("Error when receiving data from socket: %d", e); return false; } if (n == 0) { RAWLOG_ERROR("Connection gracefully closed before we send any data"); return false; } if (verbose) RAWTRACE1("Actually read %d bytes", n); r.insert(r.end(), &buf[0], &buf[0] + n); } if (!r.empty()) { request.insert(request.end(), r.begin(), r.end()); if ( !rho_conf_getBool("log_skip_post") ) RAWTRACE1("Received request:\n%s", &request[0]); } return true; } bool CHttpServer::send_response_impl(String const &data, bool continuation) { if (verbose) { if (continuation) RAWTRACE("Send continuation data..."); else RAWTRACE("Sending response..."); } // First of all, make socket blocking #if defined(WINDOWS_PLATFORM) unsigned long optval = 0; if(::ioctlsocket(m_sock, FIONBIO, &optval) == SOCKET_ERROR) { RAWLOG_ERROR1("Can not set blocking socket mode: %d", RHO_NET_ERROR_CODE); return false; } #else int flags = fcntl(m_sock, F_GETFL); if (flags == -1) { RAWLOG_ERROR1("Can not get current socket mode: %d", errno); return false; } if (fcntl(m_sock, F_SETFL, flags & ~O_NONBLOCK) == -1) { RAWLOG_ERROR1("Can not set blocking socket mode: %d", errno); return false; } #endif size_t pos = 0; for(; pos < data.size();) { int n = send(m_sock, data.c_str() + pos, data.size() - pos, 0); if (n == -1) { int e = RHO_NET_ERROR_CODE; #if !defined(WINDOWS_PLATFORM) if (e == EINTR) continue; #endif RAWLOG_ERROR1("Can not send response data: %d", e); return false; } if (n == 0) break; pos += n; } //String dbg_response = response.size() > 100 ? response.substr(0, 100) : response; //RAWTRACE2("Sent response:\n%s%s", dbg_response.c_str(), response.size() > 100 ? "..." : " "); if (continuation) RAWTRACE1("Sent response body: %d bytes", data.size()); else if ( !rho_conf_getBool("log_skip_post") ) RAWTRACE1("Sent response (only headers displayed):\n%s", data.c_str()); return true; } bool CHttpServer::send_response(String const &response, bool redirect) { #ifdef OS_ANDROID if (redirect) { CAutoPtr<IRhoThreadImpl> ptrThread = rho_get_RhoClassFactory()->createThreadImpl(); ptrThread->sleep(20); } #endif return send_response_impl(response, false); } String CHttpServer::create_response(String const &reason) { return create_response(reason, ""); } String CHttpServer::create_response(String const &reason, HeaderList const &headers) { return create_response(reason, headers, ""); } String CHttpServer::create_response(String const &reason, String const &body) { return create_response(reason, HeaderList(), body); } String CHttpServer::create_response(String const &reason, HeaderList const &hdrs, String const &body) { String response = "HTTP/1.1 "; response += reason; response += "\r\n"; char buf[50]; snprintf(buf, sizeof(buf), "%d", m_port); HeaderList headers; headers.push_back(Header("Host", String("127.0.0.1:") + buf)); headers.push_back(Header("Connection", "close")); std::copy(hdrs.begin(), hdrs.end(), std::back_inserter(headers)); for(HeaderList::const_iterator it = headers.begin(), lim = headers.end(); it != lim; ++it) { response += it->name; response += ": "; response += it->value; response += "\r\n"; } response += "\r\n"; response += body; return response; }
int CryptoManager::verify_callback(int preverify_ok, X509_STORE_CTX *ctx) { int err = X509_STORE_CTX_get_error(ctx); SSL* ssl = (SSL*)X509_STORE_CTX_get_ex_data(ctx, SSL_get_ex_data_X509_STORE_CTX_idx()); SSLVerifyData* verifyData = (SSLVerifyData*)SSL_get_ex_data(ssl, CryptoManager::idxVerifyData); // TODO: we should make sure that the trusted certificate store never overules KeyPrint, if present, because certificate pinning on an individual certificate is a stronger method of verification. // verifyData is unset only when KeyPrint has been pinned and we are not skipping errors due to incomplete chains // we can fail here f.ex. if the certificate has expired but is still pinned with KeyPrint if (!verifyData) return preverify_ok; bool allowUntrusted = verifyData->first; string keyp = verifyData->second; if (!keyp.empty()) { X509* cert = X509_STORE_CTX_get_current_cert(ctx); if (!cert) return 0; string kp2(keyp); if (kp2.compare(0, 12, "trusted_keyp") == 0) { // Possible follow up errors, after verification of a partial chain if (err == X509_V_ERR_CERT_UNTRUSTED || err == X509_V_ERR_UNABLE_TO_VERIFY_LEAF_SIGNATURE) { X509_STORE_CTX_set_error(ctx, X509_V_OK); return 1; } } else if (kp2.compare(0, 7, "SHA256/") != 0) return allowUntrusted ? 1 : 0; ByteVector kp = ssl::X509_digest(cert, EVP_sha256()); ByteVector kp2v(kp.size()); Encoder::fromBase32(&kp2[7], &kp2v[0], kp2v.size()); if (std::equal(kp.begin(), kp.end(), kp2v.begin())) { // KeyPrint validated, we can get rid of it (to avoid unnecessary passes) SSL_set_ex_data(ssl, CryptoManager::idxVerifyData, NULL); if (err != X509_V_OK) { // This is the right way to get the certificate store, although it is rather roundabout X509_STORE* store = SSL_CTX_get_cert_store(SSL_get_SSL_CTX(ssl)); dcassert(store == ctx->ctx); // Hide the potential library error about trying to add a dupe ERR_set_mark(); if (X509_STORE_add_cert(store, cert)) { X509_STORE_CTX_set_error(ctx, X509_V_OK); X509_verify_cert(ctx); err = X509_STORE_CTX_get_error(ctx); } else ERR_pop_to_mark(); // KeyPrint was not root certificate or we don't have the issuer certificate, the best we can do is trust the pinned KeyPrint if (err == X509_V_ERR_SELF_SIGNED_CERT_IN_CHAIN || err == X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT_LOCALLY || err == X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT) { X509_STORE_CTX_set_error(ctx, X509_V_OK); // Set this to allow ignoring any follow up errors caused by the incomplete chain SSL_set_ex_data(ssl, CryptoManager::idxVerifyData, &CryptoManager::trustedKeyprint); return 1; } } return (err == X509_V_OK) ? 1 : 0; } else { if (X509_STORE_CTX_get_error_depth(ctx) > 0) return 1; } } if (allowUntrusted) { /* // We let untrusted certificates through unconditionally, when allowed, but we like to complain if (!preverify_ok && err != X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT) { X509* cert = NULL; if ((cert = X509_STORE_CTX_get_current_cert(ctx)) != NULL) { X509_NAME* subject = X509_get_subject_name(cert); string tmp, line; tmp = getNameEntryByNID(subject, NID_commonName); if (!tmp.empty()) { CID certCID(tmp); if (certCID) tmp = Util::listToString(ClientManager::getInstance()->getNicks(certCID)); line += (!line.empty() ? ", " : "") + tmp; } tmp = getNameEntryByNID(subject, NID_organizationName); if (!tmp.empty()) line += (!line.empty() ? ", " : "") + tmp; ByteVector kp = ssl::X509_digest(cert, EVP_sha256()); string keyp = "SHA256/" + Encoder::toBase32(&kp[0], kp.size()); LogManager::getInstance()->message(STRING_F(VERIFY_CERT_FAILED, line % X509_verify_cert_error_string(err) % keyp), LogManager::LOG_INFO); } }*/ return 1; } return preverify_ok; }
void SoftwareBreakpointManager::getOpcode(uint32_t type, ByteVector &opcode) const { #if defined(OS_WIN32) && defined(ARCH_ARM) if (type == 4) { static const uint32_t WinARMBPType = 2; DS2LOG(Warning, "requesting a breakpoint of size %u on Windows ARM, " "adjusting to type %u", type, WinARMBPType); type = WinARMBPType; } #endif opcode.clear(); // TODO: We shouldn't have preprocessor checks for ARCH_ARM vs ARCH_ARM64 // because we might be an ARM64 binary debugging an ARM inferior. switch (type) { #if defined(ARCH_ARM) case 2: // udf #1 opcode.push_back('\xde'); #if defined(OS_POSIX) opcode.push_back('\x01'); #elif defined(OS_WIN32) opcode.push_back('\xfe'); #endif break; case 3: // udf.w #0 opcode.push_back('\xa0'); opcode.push_back('\x00'); opcode.push_back('\xf7'); opcode.push_back('\xf0'); break; case 4: // udf #16 opcode.push_back('\xe7'); opcode.push_back('\xf0'); opcode.push_back('\x01'); opcode.push_back('\xf0'); break; #elif defined(ARCH_ARM64) case 4: opcode.push_back('\xd4'); opcode.push_back('\x20'); opcode.push_back('\x20'); opcode.push_back('\x00'); break; #endif default: DS2LOG(Error, "invalid breakpoint type %d", type); DS2BUG("invalid breakpoint type"); break; } #if !(defined(ENDIAN_BIG) || defined(ENDIAN_LITTLE)) #error "Target not supported." #endif #if defined(ENDIAN_LITTLE) std::reverse(opcode.begin(), opcode.end()); #endif }
Byte calculateImageBrightnessFactor(const std::string& inImageFilePath) { BrightnessState state; InputFile inputFile; ByteVector brightnessValues; DistanceAndBrightnessVector valuesForAverage; inputFile.OpenFile(inImageFilePath); state.mStream = inputFile.GetInputStream(); InitializeDecodingState(state); StartRead(state); LongBufferSizeType samplesSkipping = 1; // max samples 20 if(state.mJPGState.output_width > 500) samplesSkipping = state.mJPGState.output_width / 50; // max samples - 50 else if(state.mJPGState.output_width > 20) samplesSkipping = 10; // max samples - 50 LongBufferSizeType rowsSkipping = 1; // max samples 20 if(state.mJPGState.output_height > 500) rowsSkipping = state.mJPGState.output_height / 50; // max samples - 50 else if(state.mJPGState.output_height > 20) rowsSkipping = 10; // max samples - 50 LongBufferSizeType rowCounter = 0; // read samples from image, converting to hsb and keeping the "b" component, as a brightness factor while(state.mJPGState.output_scanline < state.mJPGState.output_height) { try { state.mTotalSampleRows = jpeg_read_scanlines(&(state.mJPGState), state.mSamplesBuffer, state.mJPGState.rec_outbuf_height); ++rowCounter; if(rowCounter >= rowsSkipping) rowCounter = 0; else if(rowCounter != 1) continue; } catch(HummusJPGException) { state.mTotalSampleRows = 0; } state.mIndexInRow = 0; state.mCurrentSampleRow = 0; while(state.mCurrentSampleRow < state.mTotalSampleRows) { LongBufferSizeType row_stride = state.mJPGState.output_width * state.mJPGState.output_components; // convert samples to HSB (note that some samples are skipped) for(LongBufferSizeType i=0;i<row_stride;i+=(state.mJPGState.output_components*samplesSkipping)) { // get rgb Byte r = state.mSamplesBuffer[state.mCurrentSampleRow][i]; Byte g = state.mSamplesBuffer[state.mCurrentSampleRow][i+1]; Byte b = state.mSamplesBuffer[state.mCurrentSampleRow][i+2]; // calculate brightness [converting to HSB] brightnessValues.push_back(RGBtoHSVtoBrightness(r,g,b)); } ++state.mCurrentSampleRow; } } FinalizeDecoding(state); // prepare distance data and sort, to remove extremes from calculation ByteVector::const_iterator it = brightnessValues.begin(); for(;it!=brightnessValues.end();++it) valuesForAverage.push_back(DistanceAndBrightness(*it,calculateDistance(*it,brightnessValues))); std::sort(valuesForAverage.begin(),valuesForAverage.end(),DistanceAndBrightnessSort); // now simply calculate the average based on the first 2/3 of the vector, to reduce the effects of extremes double average = 0; DistanceAndBrightnessVector::const_iterator itCurrent = valuesForAverage.begin(); unsigned long interestingItemsCount = floor(valuesForAverage.size()*2.0/3.0); DistanceAndBrightnessVector::const_iterator itEnd = valuesForAverage.begin()+interestingItemsCount; for(itCurrent = valuesForAverage.begin();itCurrent!=itEnd;++itCurrent) average+=(double)(itCurrent->brightness)/interestingItemsCount; return ceil(average); }