void CastingPlatform<TSubClass, issueError>::issueCastError(const Item &validationError, const Item &sourceValue, const ReportContext::Ptr &context) const { Q_ASSERT(validationError); Q_ASSERT(context); Q_ASSERT(validationError.isAtomicValue()); Q_ASSERT(validationError.template as<AtomicValue>()->hasError()); const ValidationError::Ptr err(validationError.template as<ValidationError>()); QString msg(err->message()); if(msg.isNull()) { msg = QtXmlPatterns::tr("It's not possible to cast the value %1 of type %2 to %3") .arg(formatData(sourceValue.stringValue())) .arg(formatType(context->namePool(), sourceValue.type())) .arg(formatType(context->namePool(), targetType())); } else { Q_ASSERT(!msg.isEmpty()); msg = QtXmlPatterns::tr("Failure when casting from %1 to %2: %3") .arg(formatType(context->namePool(), sourceValue.type())) .arg(formatType(context->namePool(), targetType())) .arg(msg); } /* If m_errorCode is FORG0001, we assume our sub-classer doesn't have a * special wish about error code, so then we use the error object's code. */ context->error(msg, m_errorCode == ReportContext::FORG0001 ? err->errorCode() : m_errorCode, static_cast<const TSubClass*>(this)); }
AtomicComparator::Ptr ComparisonPlatform<TSubClass, issueError, comparisonType, errorCode>:: fetchComparator(const ItemType::Ptr &t1, const ItemType::Ptr &t2, const ReportContext::Ptr &context) const { Q_ASSERT(t1); Q_ASSERT(t2); if(*BuiltinTypes::xsAnyAtomicType == *t1 || *BuiltinTypes::xsAnyAtomicType == *t2 || *BuiltinTypes::item == *t1 || *BuiltinTypes::item == *t2 || *BuiltinTypes::numeric == *t1 || *BuiltinTypes::numeric == *t2 || *CommonSequenceTypes::Empty == *t1 || *CommonSequenceTypes::Empty == *t2) { /* The static type of(at least) one of the operands could not * be narrowed further, so we do the operator * lookup at runtime. */ return AtomicComparator::Ptr(); } const AtomicComparatorLocator::Ptr locator (static_cast<const AtomicType *>(t1.data())->comparatorLocator()); if(!locator) { if(issueError) { context->error(QtXmlPatterns::tr("No comparisons can be done involving the type %1.") .arg(formatType(context->namePool(), t1)), errorCode, static_cast<const TSubClass *>(this)->actualReflection()); } return AtomicComparator::Ptr(); } const AtomicComparator::Ptr comp(static_cast<const AtomicType *>(t2.data())->accept(locator, operatorID(), static_cast<const TSubClass *>(this)->actualReflection())); if(comp) return comp; else if(issueError) { context->error(QtXmlPatterns::tr("Operator %1 is not available between atomic values of type %2 and %3.") .arg(formatKeyword(AtomicComparator::displayName(operatorID(), comparisonType)), formatType(context->namePool(), t1), formatType(context->namePool(), t2)), errorCode, static_cast<const TSubClass *>(this)->actualReflection()); } return AtomicComparator::Ptr(); }
/** * Performs the actual tracing. */ Item mapToItem(const Item &item, const DynamicContext::Ptr &context) { QTextStream out(stderr); ++m_position; if(m_position == 1) { if(item) { out << qPrintable(m_msg) << " : " << qPrintable(item.stringValue()); } else { out << qPrintable(m_msg) << " : (" << qPrintable(formatType(context->namePool(), CommonSequenceTypes::Empty)) << ")\n"; return Item(); } } else { out << qPrintable(item.stringValue()) << '[' << m_position << "]\n"; } return item; }
QMap<QString, TLMethod> GeneratorNG::readMethods(const QJsonDocument &document) { const QJsonArray methods = document.object().value("methods").toArray(); QMap<QString, TLMethod> result; for (int i = 0; i < methods.count(); ++i) { const QJsonObject obj = methods.at(i).toObject(); const QString methodName = formatName(obj.value("method").toString()); const quint32 methodId = obj.value("id").toString().toInt(); TLMethod tlMethod; tlMethod.name = methodName; tlMethod.id = methodId; const QJsonArray params = obj.value("params").toArray(); foreach (const QJsonValue ¶mValue, params) { const QJsonObject ¶mObj = paramValue.toObject(); const QString paramName = formatMember(paramObj.value("name").toString()); const QString paramType = paramObj.value("type").toString(); tlMethod.params.append(TLParam(paramName, formatType(paramType))); } result.insert(methodName, tlMethod); // quint32 id = obj.value("id").toString().toInt(); // qDebug() << name << QString::number(id, 0x10); } return result; }
AtomicCaster::Ptr CastingPlatform<TSubClass, issueError>::locateCaster(const ItemType::Ptr &sourceType, const ReportContext::Ptr &context, bool &castImpossible, const SourceLocationReflection *const location, const ItemType::Ptr &targetType) { Q_ASSERT(sourceType); Q_ASSERT(targetType); const AtomicCasterLocator::Ptr locator(static_cast<AtomicType *>( targetType.data())->casterLocator()); if(!locator) { if(issueError) { context->error(QtXmlPatterns::tr("No casting is possible with %1 as the target type.") .arg(formatType(context->namePool(), targetType)), ReportContext::XPTY0004, location); } else castImpossible = true; return AtomicCaster::Ptr(); } const AtomicCaster::Ptr caster(static_cast<const AtomicType *>(sourceType.data())->accept(locator, location)); if(!caster) { if(issueError) { context->error(QtXmlPatterns::tr("It is not possible to cast from %1 to %2.") .arg(formatType(context->namePool(), sourceType)) .arg(formatType(context->namePool(), targetType)), ReportContext::XPTY0004, location); } else castImpossible = true; return AtomicCaster::Ptr(); } return caster; }
void ConvertVarType( char *typebuf, char *arraybuf, id_type id, ArrayInfo *array ) { /***************************************************************************/ char *type; if( _BaseType( id ) == TY_STRING ) { type = "String"; } else { type = convertType( id ); } formatType( typebuf, arraybuf, "", type, _IsRefType( id ), array ); }
void ConvertParmType( char *buf, char *name, id_type id, ArrayInfo *array ) { /**************************************************************************/ char *type; char arraybuf[30]; if( _BaseType( id ) == TY_STRING && array == NULL && _IsRefType( id ) ) { type = "char"; } else { type = convertType( id ); } formatType( buf, arraybuf, name, type, _IsRefType( id ), array ); strcat( buf, arraybuf ); }
QMap<QString, TLType> GeneratorNG::readTypes(const QJsonDocument &document) { const QJsonArray constructors = document.object().value("constructors").toArray(); QMap<QString, TLType> types; for (int i = 0; i < constructors.count(); ++i) { const QJsonObject obj = constructors.at(i).toObject(); const QString predicateName = formatName1stCapital(obj.value("predicate").toString()); const quint32 predicateId = obj.value("id").toString().toInt(); const QString typeName = formatType(obj.value("type").toString()); TLType tlType = types.value(typeName); tlType.name = typeName; TLSubType tlSubType; tlSubType.name = predicateName; tlSubType.id = predicateId; const QJsonArray params = obj.value("params").toArray(); foreach (const QJsonValue ¶mValue, params) { const QJsonObject ¶mObj = paramValue.toObject(); const QString paramName = formatMember(paramObj.value("name").toString()); const QString paramType = paramObj.value("type").toString(); tlSubType.members.append(TLParam(paramName, formatType(paramType))); } tlType.subTypes.append(tlSubType); types.insert(typeName, tlType); } return types; }
QString GeneratorNG::formatType(QString type) { if (plainTypes.contains(type)) { return nativeTypes.at(plainTypes.indexOf(type)); } else if (type.startsWith(QLatin1String("Vector<"))) { int firstIndex = type.indexOf(QLatin1Char('<')) + 1; int lastIndex = type.indexOf(QLatin1Char('>')); QString subType = type.mid(firstIndex, lastIndex - firstIndex); return QString("%1<%2>").arg(tlVectorType).arg(formatType(subType)); } else { type[0] = type.at(0).toUpper(); return tlPrefix + formatName(type); } }
Expression::Ptr ComparingAggregator<oper, result>::typeCheck(const StaticContext::Ptr &context, const SequenceType::Ptr &reqType) { Q_ASSERT(oper == AtomicComparator::OperatorGreaterThan || oper == AtomicComparator::OperatorLessThan); const Expression::Ptr me(FunctionCall::typeCheck(context, reqType)); ItemType::Ptr t1(m_operands.first()->staticType()->itemType()); if(*CommonSequenceTypes::Empty == *t1) return EmptySequence::create(this, context); else if(*BuiltinTypes::xsAnyAtomicType == *t1 || BuiltinTypes::numeric->xdtTypeMatches(t1)) return me; else if(BuiltinTypes::xsUntypedAtomic->xdtTypeMatches(t1)) { m_operands.replace(0, Expression::Ptr(new UntypedAtomicConverter(m_operands.first(), BuiltinTypes::xsDouble))); t1 = m_operands.first()->staticType()->itemType(); } else if(!BuiltinTypes::xsString->xdtTypeMatches(t1) && !BuiltinTypes::xsAnyURI->xdtTypeMatches(t1) && !BuiltinTypes::xsDayTimeDuration->xdtTypeMatches(t1) && !BuiltinTypes::xsDate->xdtTypeMatches(t1) && !BuiltinTypes::xsTime->xdtTypeMatches(t1) && !BuiltinTypes::xsDateTime->xdtTypeMatches(t1) && !BuiltinTypes::xsYearMonthDuration->xdtTypeMatches(t1)) { context->error(QtXmlPatterns::tr("The first argument to %1 cannot be of type %2.") .arg(QPatternist::formatFunction(context->namePool(), signature())) .arg(formatType(context->namePool(), m_operands.first()->staticType())), ReportContext::FORG0006, this); return me; } if(!m_operands.first()->staticType()->cardinality().allowsMany()) return m_operands.first(); // explicit scope needed in RVCT ComparingAggregator<oper, result>::prepareComparison(fetchComparator(t1, t1, context)); return me; }
void CastingPlatform<TSubClass, issueError>::checkTargetType(const ReportContext::Ptr &context) const { Q_ASSERT(context); const ItemType::Ptr tType(targetType()); Q_ASSERT(tType); Q_ASSERT(tType->isAtomicType()); const AtomicType::Ptr asAtomic(tType); /* This catches casting to xs:NOTATION and xs:anyAtomicType. */ if(asAtomic->isAbstract()) { context->error(QtXmlPatterns::tr("Casting to %1 is not possible because it " "is an abstract type, and can therefore never be instantiated.") .arg(formatType(context->namePool(), tType)), ReportContext::XPST0080, static_cast<const TSubClass*>(this)); } }
// This method expects a well-formatted string, there is no error checking! // Since we create those ourselves, we should be pretty safe that nobody does something crappy here. UiStyle::StyledString UiStyle::styleString(const QString &s_, quint32 baseFormat) { QString s = s_; if (s.length() > 65535) { qWarning() << QString("String too long to be styled: %1").arg(s); return StyledString(); } StyledString result; result.formatList.append(qMakePair((quint16)0, baseFormat)); quint32 curfmt = baseFormat; int pos = 0; quint16 length = 0; for (;;) { pos = s.indexOf('%', pos); if (pos < 0) break; if (s[pos+1] == '%') { // escaped %, we just remove one and continue s.remove(pos, 1); pos++; continue; } if (s[pos+1] == 'D' && s[pos+2] == 'c') { // color code if (s[pos+3] == '-') { // color off curfmt &= 0x003fffff; length = 4; } else { int color = 10 * s[pos+4].digitValue() + s[pos+5].digitValue(); //TODO: use 99 as transparent color (re mirc color "standard") color &= 0x0f; if (s[pos+3] == 'f') { curfmt &= 0xf0ffffff; curfmt |= (quint32)(color << 24) | 0x00400000; } else { curfmt &= 0x0fffffff; curfmt |= (quint32)(color << 28) | 0x00800000; } length = 6; } } else if (s[pos+1] == 'O') { // reset formatting curfmt &= 0x000000ff; // we keep message type-specific formatting length = 2; } else if (s[pos+1] == 'R') { // reverse // TODO: implement reverse formatting length = 2; } else { // all others are toggles QString code = QString("%") + s[pos+1]; if (s[pos+1] == 'D') code += s[pos+2]; FormatType ftype = formatType(code); if (ftype == Invalid) { pos++; qWarning() << (QString("Invalid format code in string: %1").arg(s)); continue; } curfmt ^= ftype; length = code.length(); } s.remove(pos, length); if (pos == result.formatList.last().first) result.formatList.last().second = curfmt; else result.formatList.append(qMakePair((quint16)pos, curfmt)); } result.plainText = s; return result; }
JNIEXPORT jint JNICALL Java_ipc_java_formatters_formatType (JNIEnv *env, jclass theClass, jlong formatter) { return (jint)(size_t)formatType((FORMAT_PTR)(size_t)formatter); }
void AccelTreeBuilder<FromDocument>::attribute(const QXmlName &name, const QStringRef &value) { /* Attributes adds a namespace binding, so lets synthesize one. * * We optimize by checking whether we have a namespace for which a binding would * be generated. Happens relatively rarely. */ if(name.hasPrefix()) namespaceBinding(QXmlName(name.namespaceURI(), 0, name.prefix())); m_document->basicData.append(AccelTree::BasicNodeData(currentDepth(), currentParent(), QXmlNodeModelIndex::Attribute, 0, name)); ++m_preNumber; ++m_size.top(); m_isPreviousAtomic = false; if(name.namespaceURI() == StandardNamespaces::xml && name.localName() == StandardLocalNames::id) { const QString normalized(value.toString().simplified()); if(QXmlUtils::isNCName(normalized)) { const QXmlName::LocalNameCode id = m_namePool->allocateLocalName(normalized); const int oldSize = m_document->m_IDs.count(); m_document->m_IDs.insert(id, currentParent()); /* We don't run the value through m_attributeCompress here, because * the likelyhood of it deing identical to another attribute is * very small. */ m_document->data.insert(m_preNumber, normalized); /** * In the case that we're called for doc-available(), m_context is * null, and we need to flag somehow that we failed to load this * document. */ if(oldSize == m_document->m_IDs.count() && m_context) // TODO { Q_ASSERT(m_context); m_context->error(QtXmlPatterns::tr("An %1-attribute with value %2 has already been declared.") .arg(formatKeyword("xml:id"), formatData(normalized)), FromDocument ? ReportContext::FODC0002 : ReportContext::XQDY0091, this); } } else if(m_context) // TODO { Q_ASSERT(m_context); /* If we're building from an XML Document(e.g, we're fed from QXmlStreamReader, we raise FODC0002, * otherwise XQDY0091. */ m_context->error(QtXmlPatterns::tr("An %1-attribute must have a " "valid %2 as value, which %3 isn't.").arg(formatKeyword("xml:id"), formatType(m_namePool, BuiltinTypes::xsNCName), formatData(value.toString())), FromDocument ? ReportContext::FODC0002 : ReportContext::XQDY0091, this); } } else m_document->data.insert(m_preNumber, *m_attributeCompress.insert(value.toString())); }
StringBuilder& FormatUtils::vformat(StringBuilder& sb, const char* fmt, va_list ap) noexcept { const char kFormatChar = '%'; const char* p = fmt; const char* mark = fmt; for (;;) { uint32_t c = static_cast<unsigned char>(*p); if (c == '\0') break; p++; // Don't continue if the character is not a formatting mark. In most cases // this branch should be taken as most of the string should be just a text. if (c != kFormatChar) continue; // NULL terminator after a formatting mark. It's safe to just break here. // The trailing mark will be appended to the string as well. However, this // is basically handling of an invalid `fmt` string. c = static_cast<unsigned char>(*p); if (c == '\0') break; // Handle a double-escaped formatting mark "%%", which produces "%". bool isEscape = (c == kFormatChar); sb.appendString(mark, (size_t)(p - mark) - 1 + isEscape); // Guess a new mark position, which is exactly two characters after the // initial mark when simple or a double-escaped mark formatting has been // used. MPSL formatting extensions will adjust the mark again. mark = ++p; if (isEscape) continue; if (c == '{') { // ---------------------------------------------------------------------- // [MPSL Formatting Extensions - '%{...}'] // ---------------------------------------------------------------------- do { c = static_cast<unsigned char>(*p); // Invalid formatting, bail out. if (c == '\0') { mark -= 2; goto _Done; } p++; } while (c != '}'); StringRef ext(mark, (size_t)(p - mark) - 1); mark = p; // Handle '%{StringRef}' passed as 'const StringRef*'. if (ext.eq("StringRef", 9)) { const StringRef* value = va_arg(ap, StringRef*); sb.appendString(value->getData(), value->getLength()); continue; } // Handle '%{Type}' passed as 'unsigned int'. if (ext.eq("Type", 4)) { unsigned int type = va_arg(ap, unsigned int); formatType(sb, type); continue; } // Handle '%{Value}' passed as 'unsigned int, const Value*'. if (ext.eq("Value", 5)) { unsigned int type = va_arg(ap, unsigned int); const Value* value = va_arg(ap, const Value*); formatValue(sb, type, value); continue; } // Handle '%{SymbolType}' passed as 'unsigned int'. if (ext.eq("SymbolType", 10)) { unsigned int value = va_arg(ap, unsigned int); sb.appendString(mpAstSymbolType[value].name); continue; }
/*static*/ StructureParser::StringVec::const_iterator StructureParser::matchCppType (StringVec::const_iterator begin, StringVec::const_iterator end, bool * result, CppType * type) { int tDepth = 0; // template depth bool modifierPart = true; // currently at left side where modifiers are StringVec::const_iterator i = begin; StringVec::const_iterator j = i == end ? end : i + 1; StringVec::const_iterator typeBegin = end; bool awaitNext = false; for (; i != end; i++){ j = i + 1; if (modifierPart){ if (*i == "static"){ if (type->static_){ // static can be there only once *result = false; return end; } type->static_ = true; continue; } if (*i == "const"){ if (type->const_){ // const can be there only once *result = false; return end; } type->const_ = true; continue; } if (*i == "mutable"){ if (type->mutable_){ // mutable can be there only once *result = false; return end; } type->mutable_ = true; continue; } // ignoring struct class forward definitions (hack?) if (*i == "struct" || *i == "class"){ *result = false; return end; } // ignoring typedef if (*i == "typedef"){ *result = false; return end; } modifierPart = false; typeBegin = i; } if (*i == "<") { tDepth++; continue; } if (*i == ">") { tDepth--; continue; } if (*i == "&" || *i == "*"){ continue; } if ((j != end && *j == "::") || *i == "::" ){ awaitNext = true; continue; } if (tDepth == 0 && i != typeBegin && !awaitNext){ // ready break; } awaitNext = false; } if (tDepth > 0) { *result = false; return end; } if (typeBegin == end){ *result = false; return end; } type->name = formatType (typeBegin, i); *result = true; return i; }
/*static*/ bool StructureParser::matchLine (char finishing) { // Case 1. Namespace definition if (mIncomingLine.size() == 2 && mIncomingLine[0] == "namespace" && finishing == '{'){ NamespaceElement * element = new NamespaceElement(); element->name = mIncomingLine[1]; push (element); return true; } // Case 2. Enum definition if (mIncomingLine.size() == 2 && mIncomingLine[0] == "enum" && finishing == '{'){ EnumElement * element = new EnumElement; element->name = mIncomingLine[1]; push (element); return true; } // Case 3. Simple Structure/Class Definition if (mIncomingLine.size() == 2 && (mIncomingLine[0] == "struct" || mIncomingLine[0] == "class") && finishing == '{'){ ClassElement * element = new ClassElement; element->name = mIncomingLine[1]; element->isStruct = (mIncomingLine[0] == "struct"); element->currentVisibility = element->isStruct ? Public : Private; push (element); return true; } // Case 4. Structure/Class derived from some other type if (mIncomingLine.size() > 3 && (mIncomingLine[0] == "struct" || mIncomingLine[0] == "class") && mIncomingLine[2] == ":"){ ClassElement * element = new ClassElement; element->name = mIncomingLine[1]; element->isStruct = (mIncomingLine[0] == "struct"); element->currentVisibility = element->isStruct ? Public : Private; StringVec::const_iterator i = mIncomingLine.begin() + 3; while (i != mIncomingLine.end()){ Visibility v = element->currentVisibility; if (*i == "public") { v = Public; i++; } if (*i == "private") { v = Private; i++; } if (*i == "protected"){ v = Protected; i++;} bool suc; StringVec::const_iterator end = matchTypeName (i, mIncomingLine.end(), &suc); if (!suc) { fprintf (stderr, "Error: could not match a typename\n"); delete element; return false; } ClassElement::Parent p; p.first = v; p.second = formatType (i,end); element->parents.push_back (p); i = end; if (i == mIncomingLine.end()) break; if (*i == ",") { i++; continue; } fprintf (stderr, "Error: Invalid character: %s\n", i->c_str()); delete element; return false; } push (element); return true; } // Case 5. Member Variable if (finishing == ';'){ VariableDefinition definition; bool result = matchVariableDefinition (mIncomingLine.begin(), mIncomingLine.end(), &definition); if (result) { if (mDebug) printf ("Matched variable definition: %s\n", sf::toJSON(definition).c_str()); StackElement * element = mStack.top(); if (element->type == StackElement::Class){ ClassElement * celement = static_cast<ClassElement*> (element); celement->memberVariables.push_back (std::make_pair(celement->currentVisibility,definition)); return true; } } } // Case 6a: Handling of SF_AUTOREFLECT_COMMAND; if (finishing == ';'){ size_t size = mIncomingLine.size(); if (size >= 1){ const std::string & x (mIncomingLine.back()); size_t prefix = beginsWidth (x, mCommandPrefix); if (prefix != x.npos){ std::string cmd = x.substr (prefix, x.npos); assert (!mStack.empty()); StackElement * element = mStack.top (); element->commands.insert (cmd); mIncomingLine.pop_back (); return true; } } } // Case 6b: handling of SF_AUTOREFLECT_COMMAND(element-name) if (finishing == ';'){ size_t size = mIncomingLine.size(); if (size >= 4){ const std::string & x (mIncomingLine.front()); size_t prefix = beginsWidth (x, mCommandPrefix); if (prefix != x.npos && mIncomingLine[1] == "(" && mIncomingLine[size-1] == ")"){ std::string cmd = x.substr (prefix, x.npos); StringVec::iterator beginType = mIncomingLine.begin() + 2; StringVec::iterator endType = mIncomingLine.end() - 1; bool suc; StringVec::const_iterator foundEnd = matchTypeName (beginType, endType, &suc); if (!suc) { fprintf (stderr, "Could not match a type name in %s command", cmd.c_str()); return false; } std::string elementName = formatType (beginType, foundEnd); StackElement * parent = mStack.top (); StackElement * child = parent->findChild (elementName); if (child){ child->commands.insert (cmd); mIncomingLine.erase(mIncomingLine.end() - 4, mIncomingLine.end()); return true; } else { fprintf (stderr, "Did not found a element with name %s as child of element of name %s, for command %s\n", elementName.c_str(), sf::toJSON(parent).c_str(), cmd.c_str()); return false; } } } } // Case 7 Function declaration if (finishing == ';' || finishing == '{') { FunctionDeclarationElement * declaration = new FunctionDeclarationElement(); bool result = matchFunctionDeclaration (mIncomingLine.begin(), mIncomingLine.end(), declaration); if (result) { if (mDebug) printf ("Matched function declaration %s\n", sf::toJSON (declaration).c_str()); StackElement * element = mStack.top(); if (element->type == StackElement::Class) declaration->visibility = (static_cast<ClassElement*> (element))->currentVisibility; if ( (element->type == StackElement::Class) || (element->type == StackElement::Root) || (element->type == StackElement::Namespace)){ element->children.push_back (declaration); } else { // May happen. Regular functions are similar to be parsed like functions // E.g. int bla () { X x ();} // must not declare x but can also declare an instance of (struct/class) X, called x. // fprintf (stderr, "Matched a function declaration %s outside a class/root/namespace element, parent=%s\n", sf::toJSON (declaration).c_str(), sf::toJSON (*element).c_str()); delete declaration; if (finishing != '{') // otherwise there is still a block return true; } } if (finishing != '{') // otherwise there is still a block return true; } // Unknown block, starting if (finishing == '{'){ if (mDebug){ printf ("Unknown block start: "); for (StringVec::const_iterator i = mIncomingLine.begin(); i != mIncomingLine.end(); i++){ printf ("%s ", i->c_str()); } printf ("<stop>\n"); } UnknownBlock * element = new UnknownBlock (); push (element); return true; } // End of a block, ending if (finishing == '}'){ bool ret = pop (); return ret; } // Command, ending if (finishing == ';'){ if (mDebug){ printf ("Unknown command: "); for (StringVec::const_iterator i = mIncomingLine.begin(); i != mIncomingLine.end(); i++){ printf ("%s ", i->c_str()); } printf ("<stop>\n"); } return true; } return true; }
gl::Error Framebuffer9::readPixelsImpl(const gl::Context *context, const gl::Rectangle &area, GLenum format, GLenum type, size_t outputPitch, const gl::PixelPackState &pack, uint8_t *pixels) { const gl::FramebufferAttachment *colorbuffer = mState.getColorAttachment(0); ASSERT(colorbuffer); RenderTarget9 *renderTarget = nullptr; ANGLE_TRY(colorbuffer->getRenderTarget(context, &renderTarget)); ASSERT(renderTarget); IDirect3DSurface9 *surface = renderTarget->getSurface(); ASSERT(surface); D3DSURFACE_DESC desc; surface->GetDesc(&desc); if (desc.MultiSampleType != D3DMULTISAMPLE_NONE) { UNIMPLEMENTED(); // FIXME: Requires resolve using StretchRect into non-multisampled render target SafeRelease(surface); return gl::OutOfMemory() << "ReadPixels is unimplemented for multisampled framebuffer attachments."; } IDirect3DDevice9 *device = mRenderer->getDevice(); ASSERT(device); HRESULT result; IDirect3DSurface9 *systemSurface = nullptr; bool directToPixels = !pack.reverseRowOrder && pack.alignment <= 4 && mRenderer->getShareHandleSupport() && area.x == 0 && area.y == 0 && static_cast<UINT>(area.width) == desc.Width && static_cast<UINT>(area.height) == desc.Height && desc.Format == D3DFMT_A8R8G8B8 && format == GL_BGRA_EXT && type == GL_UNSIGNED_BYTE; if (directToPixels) { // Use the pixels ptr as a shared handle to write directly into client's memory result = device->CreateOffscreenPlainSurface(desc.Width, desc.Height, desc.Format, D3DPOOL_SYSTEMMEM, &systemSurface, reinterpret_cast<void**>(&pixels)); if (FAILED(result)) { // Try again without the shared handle directToPixels = false; } } if (!directToPixels) { result = device->CreateOffscreenPlainSurface(desc.Width, desc.Height, desc.Format, D3DPOOL_SYSTEMMEM, &systemSurface, nullptr); if (FAILED(result)) { ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY); SafeRelease(surface); return gl::OutOfMemory() << "Failed to allocate internal texture for ReadPixels."; } } result = device->GetRenderTargetData(surface, systemSurface); SafeRelease(surface); if (FAILED(result)) { SafeRelease(systemSurface); // It turns out that D3D will sometimes produce more error // codes than those documented. if (d3d9::isDeviceLostError(result)) { mRenderer->notifyDeviceLost(); } else { UNREACHABLE(); } return gl::OutOfMemory() << "Failed to read internal render target data."; } if (directToPixels) { SafeRelease(systemSurface); return gl::NoError(); } RECT rect; rect.left = gl::clamp(area.x, 0L, static_cast<LONG>(desc.Width)); rect.top = gl::clamp(area.y, 0L, static_cast<LONG>(desc.Height)); rect.right = gl::clamp(area.x + area.width, 0L, static_cast<LONG>(desc.Width)); rect.bottom = gl::clamp(area.y + area.height, 0L, static_cast<LONG>(desc.Height)); D3DLOCKED_RECT lock; result = systemSurface->LockRect(&lock, &rect, D3DLOCK_READONLY); if (FAILED(result)) { UNREACHABLE(); SafeRelease(systemSurface); return gl::OutOfMemory() << "Failed to lock internal render target."; } uint8_t *source = reinterpret_cast<uint8_t *>(lock.pBits); int inputPitch = lock.Pitch; const d3d9::D3DFormat &d3dFormatInfo = d3d9::GetD3DFormatInfo(desc.Format); gl::FormatType formatType(format, type); PackPixelsParams packParams; packParams.area.x = rect.left; packParams.area.y = rect.top; packParams.area.width = rect.right - rect.left; packParams.area.height = rect.bottom - rect.top; packParams.format = format; packParams.type = type; packParams.outputPitch = static_cast<GLuint>(outputPitch); packParams.pack = pack; PackPixels(packParams, d3dFormatInfo.info(), inputPitch, source, pixels); systemSurface->UnlockRect(); SafeRelease(systemSurface); return gl::NoError(); }
void PackPixels(const PackPixelsParams ¶ms, const angle::Format &sourceFormat, int inputPitchIn, const uint8_t *sourceIn, uint8_t *destWithoutOffset) { uint8_t *destWithOffset = destWithoutOffset + params.offset; const uint8_t *source = sourceIn; int inputPitch = inputPitchIn; if (params.pack.reverseRowOrder) { source += inputPitch * (params.area.height - 1); inputPitch = -inputPitch; } const auto &sourceGLInfo = gl::GetSizedInternalFormatInfo(sourceFormat.glInternalFormat); if (sourceGLInfo.format == params.format && sourceGLInfo.type == params.type) { // Direct copy possible for (int y = 0; y < params.area.height; ++y) { memcpy(destWithOffset + y * params.outputPitch, source + y * inputPitch, params.area.width * sourceGLInfo.pixelBytes); } return; } ASSERT(sourceGLInfo.sized); gl::FormatType formatType(params.format, params.type); ColorCopyFunction fastCopyFunc = GetFastCopyFunction(sourceFormat.fastCopyFunctions, formatType); const auto &destFormatInfo = gl::GetInternalFormatInfo(formatType.format, formatType.type); if (fastCopyFunc) { // Fast copy is possible through some special function for (int y = 0; y < params.area.height; ++y) { for (int x = 0; x < params.area.width; ++x) { uint8_t *dest = destWithOffset + y * params.outputPitch + x * destFormatInfo.pixelBytes; const uint8_t *src = source + y * inputPitch + x * sourceGLInfo.pixelBytes; fastCopyFunc(src, dest); } } return; } ColorWriteFunction colorWriteFunction = GetColorWriteFunction(formatType); // Maximum size of any Color<T> type used. uint8_t temp[16]; static_assert(sizeof(temp) >= sizeof(gl::ColorF) && sizeof(temp) >= sizeof(gl::ColorUI) && sizeof(temp) >= sizeof(gl::ColorI), "Unexpected size of gl::Color struct."); const auto &colorReadFunction = sourceFormat.colorReadFunction; for (int y = 0; y < params.area.height; ++y) { for (int x = 0; x < params.area.width; ++x) { uint8_t *dest = destWithOffset + y * params.outputPitch + x * destFormatInfo.pixelBytes; const uint8_t *src = source + y * inputPitch + x * sourceGLInfo.pixelBytes; // readFunc and writeFunc will be using the same type of color, CopyTexImage // will not allow the copy otherwise. colorReadFunction(src, temp); colorWriteFunction(temp, dest); } } }