void
nsSocketTransportService::ProbeMaxCount()
{
    NS_ASSERTION(PR_GetCurrentThread() == gSocketThread, "wrong thread");

    if (mProbedMaxCount)
        return;
    mProbedMaxCount = true;

    // Allocate and test a PR_Poll up to the gMaxCount number of unconnected
    // sockets. See bug 692260 - windows should be able to handle 1000 sockets
    // in select() without a problem, but LSPs have been known to balk at lower
    // numbers. (64 in the bug).

    // Allocate
    struct PRPollDesc pfd[SOCKET_LIMIT_TARGET];
    uint32_t numAllocated = 0;

    for (uint32_t index = 0 ; index < gMaxCount; ++index) {
        pfd[index].in_flags = PR_POLL_READ | PR_POLL_WRITE | PR_POLL_EXCEPT;
        pfd[index].out_flags = 0;
        pfd[index].fd =  PR_OpenTCPSocket(PR_AF_INET);
        if (!pfd[index].fd) {
            SOCKET_LOG(("Socket Limit Test index %d failed\n", index));
            if (index < SOCKET_LIMIT_MIN)
                gMaxCount = SOCKET_LIMIT_MIN;
            else
                gMaxCount = index;
            break;
        }
        ++numAllocated;
    }

    // Test
    PR_STATIC_ASSERT(SOCKET_LIMIT_MIN >= 32U);
    while (gMaxCount <= numAllocated) {
        int32_t rv = PR_Poll(pfd, gMaxCount, PR_MillisecondsToInterval(0));
        
        SOCKET_LOG(("Socket Limit Test poll() size=%d rv=%d\n",
                    gMaxCount, rv));

        if (rv >= 0)
            break;

        SOCKET_LOG(("Socket Limit Test poll confirmationSize=%d rv=%d error=%d\n",
                    gMaxCount, rv, PR_GetError()));

        gMaxCount -= 32;
        if (gMaxCount <= SOCKET_LIMIT_MIN) {
            gMaxCount = SOCKET_LIMIT_MIN;
            break;
        }
    }

    // Free
    for (uint32_t index = 0 ; index < numAllocated; ++index)
        if (pfd[index].fd)
            PR_Close(pfd[index].fd);

    Telemetry::Accumulate(Telemetry::NETWORK_PROBE_MAXCOUNT, gMaxCount);
    SOCKET_LOG(("Socket Limit Test max was confirmed at %d\n", gMaxCount));
}
Beispiel #2
0
  /**
   * this function is called to prepare mData for writing.  the given capacity
   * indicates the required minimum storage size for mData, in sizeof(char_type)
   * increments.  this function returns true if the operation succeeds.  it also
   * returns the old data and old flags members if mData is newly allocated.
   * the old data must be released by the caller.
   */
bool
nsTSubstring_CharT::MutatePrep( size_type capacity, char_type** oldData, uint32_t* oldFlags )
  {
    // initialize to no old data
    *oldData = nullptr;
    *oldFlags = 0;

    size_type curCapacity = Capacity();

    // If |capacity > kMaxCapacity|, then our doubling algorithm may not be
    // able to allocate it.  Just bail out in cases like that.  We don't want
    // to be allocating 2GB+ strings anyway.
    PR_STATIC_ASSERT((sizeof(nsStringBuffer) & 0x1) == 0);
    const size_type kMaxCapacity =
      (size_type(-1)/2 - sizeof(nsStringBuffer)) / sizeof(char_type) - 2;
    if (capacity > kMaxCapacity) {
      // Also assert for |capacity| equal to |size_type(-1)|, since we used to
      // use that value to flag immutability.
      NS_ASSERTION(capacity != size_type(-1), "Bogus capacity");
      return false;
    }

    // |curCapacity == 0| means that the buffer is immutable or 0-sized, so we
    // need to allocate a new buffer. We cannot use the existing buffer even
    // though it might be large enough.

    if (curCapacity != 0)
      {
        if (capacity <= curCapacity) {
          mFlags &= ~F_VOIDED;  // mutation clears voided flag
          return true;
        }

        // Use doubling algorithm when forced to increase available capacity.
        size_type temp = curCapacity;
        while (temp < capacity)
          temp <<= 1;
        NS_ASSERTION(XPCOM_MIN(temp, kMaxCapacity) >= capacity,
                     "should have hit the early return at the top");
        capacity = XPCOM_MIN(temp, kMaxCapacity);
      }

    //
    // several cases:
    //
    //  (1) we have a shared buffer (mFlags & F_SHARED)
    //  (2) we have an owned buffer (mFlags & F_OWNED)
    //  (3) we have a fixed buffer (mFlags & F_FIXED)
    //  (4) we have a readonly buffer
    //
    // requiring that we in some cases preserve the data before creating
    // a new buffer complicates things just a bit ;-)
    //

    size_type storageSize = (capacity + 1) * sizeof(char_type);

    // case #1
    if (mFlags & F_SHARED)
      {
        nsStringBuffer* hdr = nsStringBuffer::FromData(mData);
        if (!hdr->IsReadonly())
          {
            nsStringBuffer *newHdr = nsStringBuffer::Realloc(hdr, storageSize);
            if (!newHdr)
              return false; // out-of-memory (original header left intact)

            hdr = newHdr;
            mData = (char_type*) hdr->Data();
            mFlags &= ~F_VOIDED;  // mutation clears voided flag
            return true;
          }
      }

    char_type* newData;
    uint32_t newDataFlags;

      // if we have a fixed buffer of sufficient size, then use it.  this helps
      // avoid heap allocations.
    if ((mFlags & F_CLASS_FIXED) && (capacity < AsFixedString(this)->mFixedCapacity))
      {
        newData = AsFixedString(this)->mFixedBuf;
        newDataFlags = F_TERMINATED | F_FIXED;
      }
    else
      {
        // if we reach here then, we must allocate a new buffer.  we cannot
        // make use of our F_OWNED or F_FIXED buffers because they are not
        // large enough.

        nsStringBuffer* newHdr = nsStringBuffer::Alloc(storageSize).get();
        if (!newHdr)
          return false; // we are still in a consistent state

        newData = (char_type*) newHdr->Data();
        newDataFlags = F_TERMINATED | F_SHARED;
      }

    // save old data and flags
    *oldData = mData;
    *oldFlags = mFlags;

    mData = newData;
    SetDataFlags(newDataFlags);

    // mLength does not change

    // though we are not necessarily terminated at the moment, now is probably
    // still the best time to set F_TERMINATED.

    return true;
  }
nsresult
nsSVGTransformSMILAttr::AppendSVGTransformToSMILValue(
  nsIDOMSVGTransform* aTransform, nsSMILValue& aValue)
{
  NS_ASSERTION(aValue.mType == &nsSVGTransformSMILType::sSingleton,
               "Unexpected type for SMIL value");

  PRUint16 svgTransformType = nsIDOMSVGTransform::SVG_TRANSFORM_MATRIX;
  aTransform->GetType(&svgTransformType);

  nsCOMPtr<nsIDOMSVGMatrix> matrix;
  nsresult rv = aTransform->GetMatrix(getter_AddRefs(matrix));
  if (NS_FAILED(rv) || !matrix)
    return NS_ERROR_FAILURE;

  // nsSVGSMILTransform constructor should be expecting array with 3 params
  PR_STATIC_ASSERT(nsSVGSMILTransform::NUM_SIMPLE_PARAMS == 3);
  float params[3] = { 0.f };
  nsSVGSMILTransform::TransformType transformType;

  switch (svgTransformType)
  {
    case nsIDOMSVGTransform::SVG_TRANSFORM_TRANSLATE:
      {
        matrix->GetE(&params[0]);
        matrix->GetF(&params[1]);
        transformType = nsSVGSMILTransform::TRANSFORM_TRANSLATE;
      }
      break;

    case nsIDOMSVGTransform::SVG_TRANSFORM_SCALE:
      {
        matrix->GetA(&params[0]);
        matrix->GetD(&params[1]);
        transformType = nsSVGSMILTransform::TRANSFORM_SCALE;
      }
      break;

    case nsIDOMSVGTransform::SVG_TRANSFORM_ROTATE:
      {
        /*
         * Unfortunately the SVG 1.1 DOM API for transforms doesn't allow us to
         * query the center of rotation so we do some dirty casting to make up
         * for it.
         */
        nsSVGTransform* svgTransform = static_cast<nsSVGTransform*>(aTransform);
        svgTransform->GetAngle(&params[0]);
        svgTransform->GetRotationOrigin(params[1], params[2]);
        transformType = nsSVGSMILTransform::TRANSFORM_ROTATE;
      }
      break;

    case nsIDOMSVGTransform::SVG_TRANSFORM_SKEWX:
      {
        aTransform->GetAngle(&params[0]);
        transformType = nsSVGSMILTransform::TRANSFORM_SKEWX;
      }
      break;

    case nsIDOMSVGTransform::SVG_TRANSFORM_SKEWY:
      {
        aTransform->GetAngle(&params[0]);
        transformType = nsSVGSMILTransform::TRANSFORM_SKEWY;
      }
      break;

    case nsIDOMSVGTransform::SVG_TRANSFORM_MATRIX:
      {
        // nsSVGSMILTransform constructor for TRANSFORM_MATRIX type should be
        // expecting array with 6 params
        PR_STATIC_ASSERT(nsSVGSMILTransform::NUM_STORED_PARAMS == 6);
        float mx[6];
        matrix->GetA(&mx[0]);
        matrix->GetB(&mx[1]);
        matrix->GetC(&mx[2]);
        matrix->GetD(&mx[3]);
        matrix->GetE(&mx[4]);
        matrix->GetF(&mx[5]);
        return nsSVGTransformSMILType::AppendTransform(nsSVGSMILTransform(mx),
                                                       aValue);
      }

    case nsIDOMSVGTransform::SVG_TRANSFORM_UNKNOWN:
      // If it's 'unknown', it's probably not initialised, so just skip it.
      return NS_OK;

    default:
      NS_WARNING("Trying to convert unrecognised SVG transform type");
      return NS_ERROR_FAILURE;
  }

  NS_ABORT_IF_FALSE(transformType != nsSVGSMILTransform::TRANSFORM_MATRIX,
                    "generalized matrix case should have returned above");

  return nsSVGTransformSMILType::
    AppendTransform(nsSVGSMILTransform(transformType, params), aValue);
}
bool
WaveReader::LoadFormatChunk()
{
  uint32_t fmtSize, rate, channels, frameSize, sampleFormat;
  char waveFormat[WAVE_FORMAT_CHUNK_SIZE];
  const char* p = waveFormat;

  // RIFF chunks are always word (two byte) aligned.
  NS_ABORT_IF_FALSE(mDecoder->GetResource()->Tell() % 2 == 0,
                    "LoadFormatChunk called with unaligned resource");

  // The "format" chunk may not directly follow the "riff" chunk, so skip
  // over any intermediate chunks.
  if (!ScanForwardUntil(FRMT_CHUNK_MAGIC, &fmtSize)) {
    return false;
  }

  if (!ReadAll(waveFormat, sizeof(waveFormat))) {
    return false;
  }

  PR_STATIC_ASSERT(sizeof(uint16_t) +
                   sizeof(uint16_t) +
                   sizeof(uint32_t) +
                   4 +
                   sizeof(uint16_t) +
                   sizeof(uint16_t) <= sizeof(waveFormat));
  if (ReadUint16LE(&p) != WAVE_FORMAT_ENCODING_PCM) {
    NS_WARNING("WAVE is not uncompressed PCM, compressed encodings are not supported");
    return false;
  }

  channels = ReadUint16LE(&p);
  rate = ReadUint32LE(&p);

  // Skip over average bytes per second field.
  p += 4;

  frameSize = ReadUint16LE(&p);

  sampleFormat = ReadUint16LE(&p);

  // PCM encoded WAVEs are not expected to have an extended "format" chunk,
  // but I have found WAVEs that have a extended "format" chunk with an
  // extension size of 0 bytes.  Be polite and handle this rather than
  // considering the file invalid.  This code skips any extension of the
  // "format" chunk.
  if (fmtSize > WAVE_FORMAT_CHUNK_SIZE) {
    char extLength[2];
    const char* p = extLength;

    if (!ReadAll(extLength, sizeof(extLength))) {
      return false;
    }

    PR_STATIC_ASSERT(sizeof(uint16_t) <= sizeof(extLength));
    uint16_t extra = ReadUint16LE(&p);
    if (fmtSize - (WAVE_FORMAT_CHUNK_SIZE + 2) != extra) {
      NS_WARNING("Invalid extended format chunk size");
      return false;
    }
    extra += extra % 2;

    if (extra > 0) {
      PR_STATIC_ASSERT(UINT16_MAX + (UINT16_MAX % 2) < UINT_MAX / sizeof(char));
      nsAutoArrayPtr<char> chunkExtension(new char[extra]);
      if (!ReadAll(chunkExtension.get(), extra)) {
        return false;
      }
    }
  }

  // RIFF chunks are always word (two byte) aligned.
  NS_ABORT_IF_FALSE(mDecoder->GetResource()->Tell() % 2 == 0,
                    "LoadFormatChunk left resource unaligned");

  // Make sure metadata is fairly sane.  The rate check is fairly arbitrary,
  // but the channels check is intentionally limited to mono or stereo
  // because that's what the audio backend currently supports.
  unsigned int actualFrameSize = sampleFormat == 8 ? 1 : 2 * channels;
  if (rate < 100 || rate > 96000 ||
      channels < 1 || channels > MAX_CHANNELS ||
      (frameSize != 1 && frameSize != 2 && frameSize != 4) ||
      (sampleFormat != 8 && sampleFormat != 16) ||
      frameSize != actualFrameSize) {
    NS_WARNING("Invalid WAVE metadata");
    return false;
  }

  ReentrantMonitorAutoEnter monitor(mDecoder->GetReentrantMonitor());
  mSampleRate = rate;
  mChannels = channels;
  mFrameSize = frameSize;
  if (sampleFormat == 8) {
    mSampleFormat = FORMAT_U8;
  } else {
    mSampleFormat = FORMAT_S16;
  }
  return true;
}
/**
 * Translate a "rows" or "cols" spec into an array of nsFramesetSpecs
 */
nsresult
HTMLFrameSetElement::ParseRowCol(const nsAString & aValue,
                                 int32_t& aNumSpecs,
                                 nsFramesetSpec** aSpecs) 
{
  if (aValue.IsEmpty()) {
    aNumSpecs = 0;
    *aSpecs = nullptr;
    return NS_OK;
  }

  static const PRUnichar sAster('*');
  static const PRUnichar sPercent('%');
  static const PRUnichar sComma(',');

  nsAutoString spec(aValue);
  // remove whitespace (Bug 33699) and quotation marks (bug 224598)
  // also remove leading/trailing commas (bug 31482)
  spec.StripChars(" \n\r\t\"\'");
  spec.Trim(",");
  
  // Count the commas. Don't count more than X commas (bug 576447).
  PR_STATIC_ASSERT(NS_MAX_FRAMESET_SPEC_COUNT * sizeof(nsFramesetSpec) < (1 << 30));
  int32_t commaX = spec.FindChar(sComma);
  int32_t count = 1;
  while (commaX != kNotFound && count < NS_MAX_FRAMESET_SPEC_COUNT) {
    count++;
    commaX = spec.FindChar(sComma, commaX + 1);
  }

  nsFramesetSpec* specs = new nsFramesetSpec[count];
  if (!specs) {
    *aSpecs = nullptr;
    aNumSpecs = 0;
    return NS_ERROR_OUT_OF_MEMORY;
  }

  // Pre-grab the compat mode; we may need it later in the loop.
  bool isInQuirks = InNavQuirksMode(OwnerDoc());
      
  // Parse each comma separated token

  int32_t start = 0;
  int32_t specLen = spec.Length();

  for (int32_t i = 0; i < count; i++) {
    // Find our comma
    commaX = spec.FindChar(sComma, start);
    NS_ASSERTION(i == count - 1 || commaX != kNotFound,
                 "Failed to find comma, somehow");
    int32_t end = (commaX == kNotFound) ? specLen : commaX;

    // Note: If end == start then it means that the token has no
    // data in it other than a terminating comma (or the end of the spec).
    // So default to a fixed width of 0.
    specs[i].mUnit = eFramesetUnit_Fixed;
    specs[i].mValue = 0;
    if (end > start) {
      int32_t numberEnd = end;
      PRUnichar ch = spec.CharAt(numberEnd - 1);
      if (sAster == ch) {
        specs[i].mUnit = eFramesetUnit_Relative;
        numberEnd--;
      } else if (sPercent == ch) {
        specs[i].mUnit = eFramesetUnit_Percent;
        numberEnd--;
        // check for "*%"
        if (numberEnd > start) {
          ch = spec.CharAt(numberEnd - 1);
          if (sAster == ch) {
            specs[i].mUnit = eFramesetUnit_Relative;
            numberEnd--;
          }
        }
      }

      // Translate value to an integer
      nsAutoString token;
      spec.Mid(token, start, numberEnd - start);

      // Treat * as 1*
      if ((eFramesetUnit_Relative == specs[i].mUnit) &&
        (0 == token.Length())) {
        specs[i].mValue = 1;
      }
      else {
        // Otherwise just convert to integer.
        nsresult err;
        specs[i].mValue = token.ToInteger(&err);
        if (NS_FAILED(err)) {
          specs[i].mValue = 0;
        }
      }

      // Treat 0* as 1* in quirks mode (bug 40383)
      if (isInQuirks) {
        if ((eFramesetUnit_Relative == specs[i].mUnit) &&
          (0 == specs[i].mValue)) {
          specs[i].mValue = 1;
        }
      }
        
      // Catch zero and negative frame sizes for Nav compatibility
      // Nav resized absolute and relative frames to "1" and
      // percent frames to an even percentage of the width
      //
      //if (isInQuirks && (specs[i].mValue <= 0)) {
      //  if (eFramesetUnit_Percent == specs[i].mUnit) {
      //    specs[i].mValue = 100 / count;
      //  } else {
      //    specs[i].mValue = 1;
      //  }
      //} else {

      // In standards mode, just set negative sizes to zero
      if (specs[i].mValue < 0) {
        specs[i].mValue = 0;
      }
      start = end + 1;
    }
  }

  aNumSpecs = count;
  // Transfer ownership to caller here
  *aSpecs = specs;
  
  return NS_OK;
}
Beispiel #6
0
static SECStatus 
rc4_wordconv(RC4Context *cx, unsigned char *output,
             unsigned int *outputLen, unsigned int maxOutputLen,
             const unsigned char *input, unsigned int inputLen)
{
	PR_STATIC_ASSERT(sizeof(PRUword) == sizeof(ptrdiff_t));
	unsigned int inOffset = (PRUword)input % WORDSIZE;
	unsigned int outOffset = (PRUword)output % WORDSIZE;
	register WORD streamWord;
	register const WORD *pInWord;
	register WORD *pOutWord;
	register WORD inWord, nextInWord;
	PRUint8 t;
	register Stype tmpSi, tmpSj;
	register PRUint8 tmpi = cx->i;
	register PRUint8 tmpj = cx->j;
	unsigned int bufShift, invBufShift;
	unsigned int i;
	const unsigned char *finalIn;
	unsigned char *finalOut;

	PORT_Assert(maxOutputLen >= inputLen);
	if (maxOutputLen < inputLen) {
		PORT_SetError(SEC_ERROR_OUTPUT_LEN);
		return SECFailure;
	}
	if (inputLen < 2*WORDSIZE) {
		/* Ignore word conversion, do byte-at-a-time */
		return rc4_no_opt(cx, output, outputLen, maxOutputLen, input, inputLen);
	}
	*outputLen = inputLen;
	pInWord = (const WORD *)(input - inOffset);
	pOutWord = (WORD *)(output - outOffset);
	if (inOffset <= outOffset) {
		bufShift = 8*(outOffset - inOffset);
		invBufShift = 8*WORDSIZE - bufShift;
	} else {
		invBufShift = 8*(inOffset - outOffset);
		bufShift = 8*WORDSIZE - invBufShift;
	}
	/*****************************************************************/
	/* Step 1:                                                       */
	/* If the first output word is partial, consume the bytes in the */
	/* first partial output word by loading one or two words of      */
	/* input and shifting them accordingly.  Otherwise, just load    */
	/* in the first word of input.  At the end of this block, at     */
	/* least one partial word of input should ALWAYS be loaded.      */
	/*****************************************************************/
	if (outOffset) {
		unsigned int byteCount = WORDSIZE - outOffset; 
		for (i = 0; i < byteCount; i++) {
			ARCFOUR_NEXT_BYTE();
			output[i] = cx->S[t] ^ input[i];
		}
		/* Consumed byteCount bytes of input */
		inputLen -= byteCount;
		pInWord++;

		/* move to next word of output */
		pOutWord++;

		/* If buffers are relatively misaligned, shift the bytes in inWord
		 * to be aligned to the output buffer.
		 */
		if (inOffset < outOffset) {
			/* The first input word (which may be partial) has more bytes
			 * than needed.  Copy the remainder to inWord.
			 */
			unsigned int shift = LEFTMOST_BYTE_SHIFT;
			inWord = 0;
			for (i = 0; i < outOffset - inOffset; i++) {
				inWord |= (WORD)input[byteCount + i] << shift;
				shift = NEXT_BYTE_SHIFT(shift);
			}
		} else if (inOffset > outOffset) {
			/* Consumed some bytes in the second input word.  Copy the
			 * remainder to inWord.
			 */
			inWord = *pInWord++;
			inWord = inWord LSH invBufShift;
		} else {
			inWord = 0;
		}
	} else {
		/* output is word-aligned */
		if (inOffset) {
			/* Input is not word-aligned.  The first word load of input 
			 * will not produce a full word of input bytes, so one word
			 * must be pre-loaded.  The main loop below will load in the
			 * next input word and shift some of its bytes into inWord
			 * in order to create a full input word.  Note that the main
			 * loop must execute at least once because the input must
			 * be at least two words.
			 */
			unsigned int shift = LEFTMOST_BYTE_SHIFT;
			inWord = 0;
			for (i = 0; i < WORDSIZE - inOffset; i++) {
				inWord |= (WORD)input[i] << shift;
				shift = NEXT_BYTE_SHIFT(shift);
			}
			pInWord++;
		} else {
			/* Input is word-aligned.  The first word load of input 
			 * will produce a full word of input bytes, so nothing
			 * needs to be loaded here.
			 */
			inWord = 0;
		}
	}
	/*****************************************************************/
	/* Step 2: main loop                                             */
	/* At this point the output buffer is word-aligned.  Any unused  */
	/* bytes from above will be in inWord (shifted correctly).  If   */
	/* the input buffer is unaligned relative to the output buffer,  */
	/* shifting has to be done.                                      */
	/*****************************************************************/
	if (bufShift) {
		/* preloadedByteCount is the number of input bytes pre-loaded
		 * in inWord.
		 */
		unsigned int preloadedByteCount = bufShift/8;
		for (; inputLen >= preloadedByteCount + WORDSIZE;
		     inputLen -= WORDSIZE) {
			nextInWord = *pInWord++;
			inWord |= nextInWord RSH bufShift;
			nextInWord = nextInWord LSH invBufShift;
			ARCFOUR_NEXT_WORD();
			*pOutWord++ = inWord ^ streamWord;
			inWord = nextInWord;
		}
		if (inputLen == 0) {
			/* Nothing left to do. */
			cx->i = tmpi;
			cx->j = tmpj;
			return SECSuccess;
		}
		finalIn = (const unsigned char *)pInWord - preloadedByteCount;
	} else {
		for (; inputLen >= WORDSIZE; inputLen -= WORDSIZE) {
			inWord = *pInWord++;
			ARCFOUR_NEXT_WORD();
			*pOutWord++ = inWord ^ streamWord;
		}
		if (inputLen == 0) {
			/* Nothing left to do. */
			cx->i = tmpi;
			cx->j = tmpj;
			return SECSuccess;
		}
		finalIn = (const unsigned char *)pInWord;
	}
	/*****************************************************************/
	/* Step 3:                                                       */
	/* Do the remaining partial word of input one byte at a time.    */
	/*****************************************************************/
	finalOut = (unsigned char *)pOutWord;
	for (i = 0; i < inputLen; i++) {
		ARCFOUR_NEXT_BYTE();
		finalOut[i] = cx->S[t] ^ finalIn[i];
	}
	cx->i = tmpi;
	cx->j = tmpj;
	return SECSuccess;
}
Beispiel #7
0
void
nsCSSValue::AppendToString(nsCSSProperty aProperty, nsAString& aResult) const
{
  // eCSSProperty_UNKNOWN gets used for some recursive calls below.
  NS_ABORT_IF_FALSE((0 <= aProperty &&
                     aProperty <= eCSSProperty_COUNT_no_shorthands) ||
                    aProperty == eCSSProperty_UNKNOWN,
                    "property ID out of range");

  nsCSSUnit unit = GetUnit();
  if (unit == eCSSUnit_Null) {
    return;
  }

  if (eCSSUnit_String <= unit && unit <= eCSSUnit_Attr) {
    if (unit == eCSSUnit_Attr) {
      aResult.AppendLiteral("attr(");
    }
    nsAutoString  buffer;
    GetStringValue(buffer);
    if (unit == eCSSUnit_String) {
      nsStyleUtil::AppendEscapedCSSString(buffer, aResult);
    } else if (unit == eCSSUnit_Families) {
      // XXX We really need to do *some* escaping.
      aResult.Append(buffer);
    } else {
      nsStyleUtil::AppendEscapedCSSIdent(buffer, aResult);
    }
  }
  else if (eCSSUnit_Array <= unit && unit <= eCSSUnit_Steps) {
    switch (unit) {
      case eCSSUnit_Counter:  aResult.AppendLiteral("counter(");  break;
      case eCSSUnit_Counters: aResult.AppendLiteral("counters("); break;
      case eCSSUnit_Cubic_Bezier: aResult.AppendLiteral("cubic-bezier("); break;
      case eCSSUnit_Steps: aResult.AppendLiteral("steps("); break;
      default: break;
    }

    nsCSSValue::Array *array = GetArrayValue();
    bool mark = false;
    for (size_t i = 0, i_end = array->Count(); i < i_end; ++i) {
      if (aProperty == eCSSProperty_border_image && i >= 5) {
        if (array->Item(i).GetUnit() == eCSSUnit_Null) {
          continue;
        }
        if (i == 5) {
          aResult.AppendLiteral(" /");
        }
      }
      if (mark && array->Item(i).GetUnit() != eCSSUnit_Null) {
        if (unit == eCSSUnit_Array &&
            eCSSProperty_transition_timing_function != aProperty)
          aResult.AppendLiteral(" ");
        else
          aResult.AppendLiteral(", ");
      }
      if (unit == eCSSUnit_Steps && i == 1) {
        NS_ABORT_IF_FALSE(array->Item(i).GetUnit() == eCSSUnit_Enumerated &&
                          (array->Item(i).GetIntValue() ==
                            NS_STYLE_TRANSITION_TIMING_FUNCTION_STEP_START ||
                           array->Item(i).GetIntValue() ==
                            NS_STYLE_TRANSITION_TIMING_FUNCTION_STEP_END),
                          "unexpected value");
        if (array->Item(i).GetIntValue() ==
              NS_STYLE_TRANSITION_TIMING_FUNCTION_STEP_START) {
          aResult.AppendLiteral("start");
        } else {
          aResult.AppendLiteral("end");
        }
        continue;
      }
      nsCSSProperty prop =
        ((eCSSUnit_Counter <= unit && unit <= eCSSUnit_Counters) &&
         i == array->Count() - 1)
        ? eCSSProperty_list_style_type : aProperty;
      if (array->Item(i).GetUnit() != eCSSUnit_Null) {
        array->Item(i).AppendToString(prop, aResult);
        mark = true;
      }
    }
    if (eCSSUnit_Array == unit &&
        aProperty == eCSSProperty_transition_timing_function) {
      aResult.AppendLiteral(")");
    }
  }
  /* Although Function is backed by an Array, we'll handle it separately
   * because it's a bit quirky.
   */
  else if (eCSSUnit_Function == unit) {
    const nsCSSValue::Array* array = GetArrayValue();
    NS_ABORT_IF_FALSE(array->Count() >= 1,
                      "Functions must have at least one element for the name.");

    /* Append the function name. */
    const nsCSSValue& functionName = array->Item(0);
    if (functionName.GetUnit() == eCSSUnit_Enumerated) {
      // We assume that the first argument is always of nsCSSKeyword type.
      const nsCSSKeyword functionId =
        static_cast<nsCSSKeyword>(functionName.GetIntValue());
      nsStyleUtil::AppendEscapedCSSIdent(
        NS_ConvertASCIItoUTF16(nsCSSKeywords::GetStringValue(functionId)),
        aResult);
    } else {
      functionName.AppendToString(aProperty, aResult);
    }
    aResult.AppendLiteral("(");

    /* Now, step through the function contents, writing each of them as we go. */
    for (size_t index = 1; index < array->Count(); ++index) {
      array->Item(index).AppendToString(aProperty, aResult);

      /* If we're not at the final element, append a comma. */
      if (index + 1 != array->Count())
        aResult.AppendLiteral(", ");
    }

    /* Finally, append the closing parenthesis. */
    aResult.AppendLiteral(")");
  }
  else if (IsCalcUnit()) {
    NS_ABORT_IF_FALSE(GetUnit() == eCSSUnit_Calc, "unexpected unit");
    CSSValueSerializeCalcOps ops(aProperty, aResult);
    css::SerializeCalc(*this, ops);
  }
  else if (eCSSUnit_Integer == unit) {
    aResult.AppendInt(GetIntValue(), 10);
  }
  else if (eCSSUnit_Enumerated == unit) {
    if (eCSSProperty_text_decoration_line == aProperty) {
      PRInt32 intValue = GetIntValue();
      if (NS_STYLE_TEXT_DECORATION_LINE_NONE == intValue) {
        AppendASCIItoUTF16(nsCSSProps::LookupPropertyValue(aProperty, intValue),
                           aResult);
      } else {
        // Ignore the "override all" internal value.
        // (It doesn't have a string representation.)
        intValue &= ~NS_STYLE_TEXT_DECORATION_LINE_OVERRIDE_ALL;
        nsStyleUtil::AppendBitmaskCSSValue(
          aProperty, intValue,
          NS_STYLE_TEXT_DECORATION_LINE_UNDERLINE,
          NS_STYLE_TEXT_DECORATION_LINE_PREF_ANCHORS,
          aResult);
      }
    }
    else if (eCSSProperty_marks == aProperty) {
      PRInt32 intValue = GetIntValue();
      if (intValue == NS_STYLE_PAGE_MARKS_NONE) {
        AppendASCIItoUTF16(nsCSSProps::LookupPropertyValue(aProperty, intValue),
                           aResult);
      } else {
        nsStyleUtil::AppendBitmaskCSSValue(aProperty, intValue,
                                           NS_STYLE_PAGE_MARKS_CROP,
                                           NS_STYLE_PAGE_MARKS_REGISTER,
                                           aResult);
      }
    }
    else if (eCSSProperty_unicode_bidi == aProperty) {
      PR_STATIC_ASSERT(NS_STYLE_UNICODE_BIDI_NORMAL == 0);
      PRInt32 intValue = GetIntValue();
      if (NS_STYLE_UNICODE_BIDI_NORMAL == intValue) {
        AppendASCIItoUTF16(nsCSSProps::LookupPropertyValue(aProperty, intValue),
                           aResult);
      } else {
        nsStyleUtil::AppendBitmaskCSSValue(
          aProperty, intValue,
          NS_STYLE_UNICODE_BIDI_EMBED,
          NS_STYLE_UNICODE_BIDI_PLAINTEXT,
          aResult);
      }
    }
    else {
      const nsAFlatCString& name = nsCSSProps::LookupPropertyValue(aProperty, GetIntValue());
      AppendASCIItoUTF16(name, aResult);
    }
  }
  else if (eCSSUnit_EnumColor == unit) {
    // we can lookup the property in the ColorTable and then
    // get a string mapping the name
    nsCAutoString str;
    if (nsCSSProps::GetColorName(GetIntValue(), str)){
      AppendASCIItoUTF16(str, aResult);
    } else {
      NS_ABORT_IF_FALSE(false, "bad color value");
    }
  }
  else if (eCSSUnit_Color == unit) {
    nscolor color = GetColorValue();
    if (color == NS_RGBA(0, 0, 0, 0)) {
      // Use the strictest match for 'transparent' so we do correct
      // round-tripping of all other rgba() values.
      aResult.AppendLiteral("transparent");
    } else {
      PRUint8 a = NS_GET_A(color);
      if (a < 255) {
        aResult.AppendLiteral("rgba(");
      } else {
        aResult.AppendLiteral("rgb(");
      }

      NS_NAMED_LITERAL_STRING(comma, ", ");

      aResult.AppendInt(NS_GET_R(color), 10);
      aResult.Append(comma);
      aResult.AppendInt(NS_GET_G(color), 10);
      aResult.Append(comma);
      aResult.AppendInt(NS_GET_B(color), 10);
      if (a < 255) {
        aResult.Append(comma);
        aResult.AppendFloat(nsStyleUtil::ColorComponentToFloat(a));
      }
      aResult.Append(PRUnichar(')'));
    }
  }
  else if (eCSSUnit_URL == unit || eCSSUnit_Image == unit) {
    aResult.Append(NS_LITERAL_STRING("url("));
    nsStyleUtil::AppendEscapedCSSString(
      nsDependentString(GetOriginalURLValue()), aResult);
    aResult.Append(NS_LITERAL_STRING(")"));
  }
  else if (eCSSUnit_Element == unit) {
    aResult.Append(NS_LITERAL_STRING("-moz-element(#"));
    nsAutoString tmpStr;
    GetStringValue(tmpStr);
    nsStyleUtil::AppendEscapedCSSIdent(tmpStr, aResult);
    aResult.Append(NS_LITERAL_STRING(")"));
  }
  else if (eCSSUnit_Percent == unit) {
    aResult.AppendFloat(GetPercentValue() * 100.0f);
  }
  else if (eCSSUnit_Percent < unit) {  // length unit
    aResult.AppendFloat(GetFloatValue());
  }
  else if (eCSSUnit_Gradient == unit) {
    nsCSSValueGradient* gradient = GetGradientValue();

    if (gradient->mIsRepeating) {
      if (gradient->mIsRadial)
        aResult.AppendLiteral("-moz-repeating-radial-gradient(");
      else
        aResult.AppendLiteral("-moz-repeating-linear-gradient(");
    } else {
      if (gradient->mIsRadial)
        aResult.AppendLiteral("-moz-radial-gradient(");
      else
        aResult.AppendLiteral("-moz-linear-gradient(");
    }

    if (gradient->mBgPos.mXValue.GetUnit() != eCSSUnit_None ||
        gradient->mBgPos.mYValue.GetUnit() != eCSSUnit_None ||
        gradient->mAngle.GetUnit() != eCSSUnit_None) {
      if (gradient->mBgPos.mXValue.GetUnit() != eCSSUnit_None) {
        gradient->mBgPos.mXValue.AppendToString(eCSSProperty_background_position,
                                                aResult);
        aResult.AppendLiteral(" ");
      }
      if (gradient->mBgPos.mXValue.GetUnit() != eCSSUnit_None) {
        gradient->mBgPos.mYValue.AppendToString(eCSSProperty_background_position,
                                                aResult);
        aResult.AppendLiteral(" ");
      }
      if (gradient->mAngle.GetUnit() != eCSSUnit_None) {
        gradient->mAngle.AppendToString(aProperty, aResult);
      }
      aResult.AppendLiteral(", ");
    }

    if (gradient->mIsRadial &&
        (gradient->mRadialShape.GetUnit() != eCSSUnit_None ||
         gradient->mRadialSize.GetUnit() != eCSSUnit_None)) {
      if (gradient->mRadialShape.GetUnit() != eCSSUnit_None) {
        NS_ABORT_IF_FALSE(gradient->mRadialShape.GetUnit() ==
                          eCSSUnit_Enumerated,
                          "bad unit for radial gradient shape");
        PRInt32 intValue = gradient->mRadialShape.GetIntValue();
        NS_ABORT_IF_FALSE(intValue != NS_STYLE_GRADIENT_SHAPE_LINEAR,
                          "radial gradient with linear shape?!");
        AppendASCIItoUTF16(nsCSSProps::ValueToKeyword(intValue,
                               nsCSSProps::kRadialGradientShapeKTable),
                           aResult);
        aResult.AppendLiteral(" ");
      }

      if (gradient->mRadialSize.GetUnit() != eCSSUnit_None) {
        NS_ABORT_IF_FALSE(gradient->mRadialSize.GetUnit() ==
                          eCSSUnit_Enumerated,
                          "bad unit for radial gradient size");
        PRInt32 intValue = gradient->mRadialSize.GetIntValue();
        AppendASCIItoUTF16(nsCSSProps::ValueToKeyword(intValue,
                               nsCSSProps::kRadialGradientSizeKTable),
                           aResult);
      }
      aResult.AppendLiteral(", ");
    }

    for (PRUint32 i = 0 ;;) {
      gradient->mStops[i].mColor.AppendToString(aProperty, aResult);
      if (gradient->mStops[i].mLocation.GetUnit() != eCSSUnit_None) {
        aResult.AppendLiteral(" ");
        gradient->mStops[i].mLocation.AppendToString(aProperty, aResult);
      }
      if (++i == gradient->mStops.Length()) {
        break;
      }
      aResult.AppendLiteral(", ");
    }

    aResult.AppendLiteral(")");
  } else if (eCSSUnit_Pair == unit) {
    GetPairValue().AppendToString(aProperty, aResult);
  } else if (eCSSUnit_Triplet == unit) {
    GetTripletValue().AppendToString(aProperty, aResult);
  } else if (eCSSUnit_Rect == unit) {
    GetRectValue().AppendToString(aProperty, aResult);
  } else if (eCSSUnit_List == unit || eCSSUnit_ListDep == unit) {
    GetListValue()->AppendToString(aProperty, aResult);
  } else if (eCSSUnit_PairList == unit || eCSSUnit_PairListDep == unit) {
    GetPairListValue()->AppendToString(aProperty, aResult);
  }

  switch (unit) {
    case eCSSUnit_Null:         break;
    case eCSSUnit_Auto:         aResult.AppendLiteral("auto");     break;
    case eCSSUnit_Inherit:      aResult.AppendLiteral("inherit");  break;
    case eCSSUnit_Initial:      aResult.AppendLiteral("-moz-initial"); break;
    case eCSSUnit_None:         aResult.AppendLiteral("none");     break;
    case eCSSUnit_Normal:       aResult.AppendLiteral("normal");   break;
    case eCSSUnit_System_Font:  aResult.AppendLiteral("-moz-use-system-font"); break;
    case eCSSUnit_All:          aResult.AppendLiteral("all"); break;
    case eCSSUnit_Dummy:
    case eCSSUnit_DummyInherit:
      NS_ABORT_IF_FALSE(false, "should never serialize");
      break;

    case eCSSUnit_String:       break;
    case eCSSUnit_Ident:        break;
    case eCSSUnit_Families:     break;
    case eCSSUnit_URL:          break;
    case eCSSUnit_Image:        break;
    case eCSSUnit_Element:      break;
    case eCSSUnit_Array:        break;
    case eCSSUnit_Attr:
    case eCSSUnit_Cubic_Bezier:
    case eCSSUnit_Steps:
    case eCSSUnit_Counter:
    case eCSSUnit_Counters:     aResult.Append(PRUnichar(')'));    break;
    case eCSSUnit_Local_Font:   break;
    case eCSSUnit_Font_Format:  break;
    case eCSSUnit_Function:     break;
    case eCSSUnit_Calc:         break;
    case eCSSUnit_Calc_Plus:    break;
    case eCSSUnit_Calc_Minus:   break;
    case eCSSUnit_Calc_Times_L: break;
    case eCSSUnit_Calc_Times_R: break;
    case eCSSUnit_Calc_Divided: break;
    case eCSSUnit_Integer:      break;
    case eCSSUnit_Enumerated:   break;
    case eCSSUnit_EnumColor:    break;
    case eCSSUnit_Color:        break;
    case eCSSUnit_Percent:      aResult.Append(PRUnichar('%'));    break;
    case eCSSUnit_Number:       break;
    case eCSSUnit_Gradient:     break;
    case eCSSUnit_Pair:         break;
    case eCSSUnit_Triplet:      break;
    case eCSSUnit_Rect:         break;
    case eCSSUnit_List:         break;
    case eCSSUnit_ListDep:      break;
    case eCSSUnit_PairList:     break;
    case eCSSUnit_PairListDep:  break;

    case eCSSUnit_Inch:         aResult.AppendLiteral("in");   break;
    case eCSSUnit_Millimeter:   aResult.AppendLiteral("mm");   break;
    case eCSSUnit_PhysicalMillimeter: aResult.AppendLiteral("mozmm");   break;
    case eCSSUnit_Centimeter:   aResult.AppendLiteral("cm");   break;
    case eCSSUnit_Point:        aResult.AppendLiteral("pt");   break;
    case eCSSUnit_Pica:         aResult.AppendLiteral("pc");   break;

    case eCSSUnit_EM:           aResult.AppendLiteral("em");   break;
    case eCSSUnit_XHeight:      aResult.AppendLiteral("ex");   break;
    case eCSSUnit_Char:         aResult.AppendLiteral("ch");   break;
    case eCSSUnit_RootEM:       aResult.AppendLiteral("rem");  break;

    case eCSSUnit_Pixel:        aResult.AppendLiteral("px");   break;

    case eCSSUnit_Degree:       aResult.AppendLiteral("deg");  break;
    case eCSSUnit_Grad:         aResult.AppendLiteral("grad"); break;
    case eCSSUnit_Radian:       aResult.AppendLiteral("rad");  break;

    case eCSSUnit_Hertz:        aResult.AppendLiteral("Hz");   break;
    case eCSSUnit_Kilohertz:    aResult.AppendLiteral("kHz");  break;

    case eCSSUnit_Seconds:      aResult.Append(PRUnichar('s'));    break;
    case eCSSUnit_Milliseconds: aResult.AppendLiteral("ms");   break;
  }
}
Beispiel #8
0
nsresult
Key::EncodeJSVal(JSContext* aCx, const jsval aVal, PRUint8 aTypeOffset)
{
  PR_STATIC_ASSERT(eMaxType * MaxArrayCollapse < 256);

  if (JSVAL_IS_STRING(aVal)) {
    nsDependentJSString str;
    if (!str.init(aCx, aVal)) {
      return NS_ERROR_OUT_OF_MEMORY;
    }
    EncodeString(str, aTypeOffset);
    return NS_OK;
  }

  if (JSVAL_IS_INT(aVal)) {
    EncodeNumber((double)JSVAL_TO_INT(aVal), eFloat + aTypeOffset);
    return NS_OK;
  }

  if (JSVAL_IS_DOUBLE(aVal)) {
    double d = JSVAL_TO_DOUBLE(aVal);
    if (DOUBLE_IS_NaN(d)) {
      return NS_ERROR_DOM_INDEXEDDB_DATA_ERR;
    }
    EncodeNumber(d, eFloat + aTypeOffset);
    return NS_OK;
  }

  if (!JSVAL_IS_PRIMITIVE(aVal)) {
    JSObject* obj = JSVAL_TO_OBJECT(aVal);
    if (JS_IsArrayObject(aCx, obj)) {
      aTypeOffset += eMaxType;

      if (aTypeOffset == eMaxType * MaxArrayCollapse) {
        mBuffer.Append(aTypeOffset);
        aTypeOffset = 0;
      }
      NS_ASSERTION((aTypeOffset % eMaxType) == 0 &&
                   aTypeOffset < (eMaxType * MaxArrayCollapse),
                   "Wrong typeoffset");

      jsuint length;
      if (!JS_GetArrayLength(aCx, obj, &length)) {
        return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
      }

      for (jsuint index = 0; index < length; index++) {
        jsval val;
        if (!JS_GetElement(aCx, obj, index, &val)) {
          return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
        }

        nsresult rv = EncodeJSVal(aCx, val, aTypeOffset);
        NS_ENSURE_SUCCESS(rv, rv);

        aTypeOffset = 0;
      }

      mBuffer.Append(eTerminator + aTypeOffset);

      return NS_OK;
    }

    if (JS_ObjectIsDate(aCx, obj)) {
      EncodeNumber(js_DateGetMsecSinceEpoch(aCx, obj), eDate + aTypeOffset);
      return NS_OK;
    }
  }

  return NS_ERROR_DOM_INDEXEDDB_DATA_ERR;
}
Beispiel #9
0
bool
WaveReader::LoadAllChunks(nsAutoPtr<nsHTMLMediaElement::MetadataTags> &aTags)
{
  // Chunks are always word (two byte) aligned.
  NS_ABORT_IF_FALSE(mDecoder->GetResource()->Tell() % 2 == 0,
                    "LoadAllChunks called with unaligned resource");

  bool loadFormatChunk = false;
  bool findDataOffset = false;

  for (;;) {
    static const unsigned int CHUNK_HEADER_SIZE = 8;
    char chunkHeader[CHUNK_HEADER_SIZE];
    const char* p = chunkHeader;

    if (!ReadAll(chunkHeader, sizeof(chunkHeader))) {
      return false;
    }

    PR_STATIC_ASSERT(sizeof(uint32_t) * 2 <= CHUNK_HEADER_SIZE);

    uint32_t magic = ReadUint32BE(&p);
    uint32_t chunkSize = ReadUint32LE(&p);
    int64_t chunkStart = GetPosition();

    switch (magic) {
      case FRMT_CHUNK_MAGIC:
        loadFormatChunk = LoadFormatChunk(chunkSize);
        if (!loadFormatChunk) {
          return false;
        }
        break;

      case LIST_CHUNK_MAGIC:
        if (!aTags) {
          LoadListChunk(chunkSize, aTags);
        }
        break;

      case DATA_CHUNK_MAGIC:
        findDataOffset = FindDataOffset(chunkSize);
        return loadFormatChunk && findDataOffset;

      default:
        break;
    }

    // RIFF chunks are two-byte aligned, so round up if necessary.
    chunkSize += chunkSize % 2;

    // Move forward to next chunk
    CheckedInt64 forward = CheckedInt64(chunkStart) + chunkSize - GetPosition();

    if (!forward.isValid() || forward.value() < 0) {
      return false;
    }

    static const int64_t MAX_CHUNK_SIZE = 1 << 16;
    PR_STATIC_ASSERT(uint64_t(MAX_CHUNK_SIZE) < UINT_MAX / sizeof(char));
    nsAutoArrayPtr<char> chunk(new char[MAX_CHUNK_SIZE]);
    while (forward.value() > 0) {
      int64_t size = NS_MIN(forward.value(), MAX_CHUNK_SIZE);
      if (!ReadAll(chunk.get(), size)) {
        return false;
      }
      forward -= size;
    }
  }

  return false;
}
Beispiel #10
0
bool
WaveReader::LoadListChunk(uint32_t aChunkSize,
    nsAutoPtr<nsHTMLMediaElement::MetadataTags> &aTags)
{
  // List chunks are always word (two byte) aligned.
  NS_ABORT_IF_FALSE(mDecoder->GetResource()->Tell() % 2 == 0,
                    "LoadListChunk called with unaligned resource");

  static const unsigned int MAX_CHUNK_SIZE = 1 << 16;
  PR_STATIC_ASSERT(MAX_CHUNK_SIZE < UINT_MAX / sizeof(char));

  if (aChunkSize > MAX_CHUNK_SIZE) {
    return false;
  }

  nsAutoArrayPtr<char> chunk(new char[aChunkSize]);
  if (!ReadAll(chunk.get(), aChunkSize)) {
    return false;
  }

  static const uint32_t INFO_LIST_MAGIC = 0x494e464f;
  const char *p = chunk.get();
  if (ReadUint32BE(&p) != INFO_LIST_MAGIC) {
    return false;
  }

  const waveIdToName ID_TO_NAME[] = {
    { 0x49415254, NS_LITERAL_CSTRING("artist") },   // IART
    { 0x49434d54, NS_LITERAL_CSTRING("comments") }, // ICMT
    { 0x49474e52, NS_LITERAL_CSTRING("genre") },    // IGNR
    { 0x494e414d, NS_LITERAL_CSTRING("name") },     // INAM
  };

  const char* const end = chunk.get() + aChunkSize;

  aTags = new nsHTMLMediaElement::MetadataTags;
  aTags->Init();

  while (p + 8 < end) {
    uint32_t id = ReadUint32BE(&p);
    // Uppercase tag id, inspired by GStreamer's Wave parser.
    id &= 0xDFDFDFDF;

    uint32_t length = ReadUint32LE(&p);

    // Subchunk shall not exceed parent chunk.
    if (p + length > end) {
      break;
    }

    nsCString val(p, length);
    if (val[length - 1] == '\0') {
      val.SetLength(length - 1);
    }

    // Chunks in List::INFO are always word (two byte) aligned. So round up if
    // necessary.
    length += length % 2;
    p += length;

    if (!IsUTF8(val)) {
      continue;
    }

    for (size_t i = 0; i < mozilla::ArrayLength(ID_TO_NAME); ++i) {
      if (id == ID_TO_NAME[i].id) {
        aTags->Put(ID_TO_NAME[i].name, val);
        break;
      }
    }
  }

  return true;
}
Beispiel #11
0
SECStatus
PRNGTEST_RunHealthTests()
{
    static const PRUint8 entropy[] = {
        0x8e, 0x9c, 0x0d, 0x25, 0x75, 0x22, 0x04, 0xf9,
        0xc5, 0x79, 0x10, 0x8b, 0x23, 0x79, 0x37, 0x14,
        0x9f, 0x2c, 0xc7, 0x0b, 0x39, 0xf8, 0xee, 0xef,
        0x95, 0x0c, 0x97, 0x59, 0xfc, 0x0a, 0x85, 0x41,
        0x76, 0x9d, 0x6d, 0x67, 0x00, 0x4e, 0x19, 0x12,
        0x02, 0x16, 0x53, 0xea, 0xf2, 0x73, 0xd7, 0xd6,
        0x7f, 0x7e, 0xc8, 0xae, 0x9c, 0x09, 0x99, 0x7d,
        0xbb, 0x9e, 0x48, 0x7f, 0xbb, 0x96, 0x46, 0xb3,
        0x03, 0x75, 0xf8, 0xc8, 0x69, 0x45, 0x3f, 0x97,
        0x5e, 0x2e, 0x48, 0xe1, 0x5d, 0x58, 0x97, 0x4c
    };
    static const PRUint8 rng_known_result[] = {
        0x16, 0xe1, 0x8c, 0x57, 0x21, 0xd8, 0xf1, 0x7e,
        0x5a, 0xa0, 0x16, 0x0b, 0x7e, 0xa6, 0x25, 0xb4,
        0x24, 0x19, 0xdb, 0x54, 0xfa, 0x35, 0x13, 0x66,
        0xbb, 0xaa, 0x2a, 0x1b, 0x22, 0x33, 0x2e, 0x4a,
        0x14, 0x07, 0x9d, 0x52, 0xfc, 0x73, 0x61, 0x48,
        0xac, 0xc1, 0x22, 0xfc, 0xa4, 0xfc, 0xac, 0xa4,
        0xdb, 0xda, 0x5b, 0x27, 0x33, 0xc4, 0xb3
    };
    static const PRUint8 reseed_entropy[] = {
        0xc6, 0x0b, 0x0a, 0x30, 0x67, 0x07, 0xf4, 0xe2,
        0x24, 0xa7, 0x51, 0x6f, 0x5f, 0x85, 0x3e, 0x5d,
        0x67, 0x97, 0xb8, 0x3b, 0x30, 0x9c, 0x7a, 0xb1,
        0x52, 0xc6, 0x1b, 0xc9, 0x46, 0xa8, 0x62, 0x79
    };
    static const PRUint8 additional_input[] = {
        0x86, 0x82, 0x28, 0x98, 0xe7, 0xcb, 0x01, 0x14,
        0xae, 0x87, 0x4b, 0x1d, 0x99, 0x1b, 0xc7, 0x41,
        0x33, 0xff, 0x33, 0x66, 0x40, 0x95, 0x54, 0xc6,
        0x67, 0x4d, 0x40, 0x2a, 0x1f, 0xf9, 0xeb, 0x65
    };
    static const PRUint8 rng_reseed_result[] = {
        0x02, 0x0c, 0xc6, 0x17, 0x86, 0x49, 0xba, 0xc4,
        0x7b, 0x71, 0x35, 0x05, 0xf0, 0xdb, 0x4a, 0xc2,
        0x2c, 0x38, 0xc1, 0xa4, 0x42, 0xe5, 0x46, 0x4a,
        0x7d, 0xf0, 0xbe, 0x47, 0x88, 0xb8, 0x0e, 0xc6,
        0x25, 0x2b, 0x1d, 0x13, 0xef, 0xa6, 0x87, 0x96,
        0xa3, 0x7d, 0x5b, 0x80, 0xc2, 0x38, 0x76, 0x61,
        0xc7, 0x80, 0x5d, 0x0f, 0x05, 0x76, 0x85
    };
    static const PRUint8 rng_no_reseed_result[] = {
        0xc4, 0x40, 0x41, 0x8c, 0xbf, 0x2f, 0x70, 0x23,
        0x88, 0xf2, 0x7b, 0x30, 0xc3, 0xca, 0x1e, 0xf3,
        0xef, 0x53, 0x81, 0x5d, 0x30, 0xed, 0x4c, 0xf1,
        0xff, 0x89, 0xa5, 0xee, 0x92, 0xf8, 0xc0, 0x0f,
        0x88, 0x53, 0xdf, 0xb6, 0x76, 0xf0, 0xaa, 0xd3,
        0x2e, 0x1d, 0x64, 0x37, 0x3e, 0xe8, 0x4a, 0x02,
        0xff, 0x0a, 0x7f, 0xe5, 0xe9, 0x2b, 0x6d
    };

    SECStatus rng_status = SECSuccess;
    PR_STATIC_ASSERT(sizeof(rng_known_result) >= sizeof(rng_reseed_result));
    PRUint8 result[sizeof(rng_known_result)];

    /********************************************/
    /*   First test instantiate error path.     */
    /*   In this case we supply enough entropy, */
    /*   but not enough seed. This will trigger */
    /*   the code that checks for a entropy     */
    /*   source failure.                        */
    /********************************************/
    rng_status = PRNGTEST_Instantiate(entropy, 256 / PR_BITS_PER_BYTE,
                                      NULL, 0, NULL, 0);
    if (rng_status == SECSuccess) {
        PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
        return SECFailure;
    }
    if (PORT_GetError() != SEC_ERROR_NEED_RANDOM) {
        PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
        return SECFailure;
    }
    /* we failed with the proper error code, we can continue */

    /********************************************/
    /* Generate random bytes with a known seed. */
    /********************************************/
    rng_status = PRNGTEST_Instantiate(entropy, sizeof entropy,
                                      NULL, 0, NULL, 0);
    if (rng_status != SECSuccess) {
        /* Error set by PRNGTEST_Instantiate */
        return SECFailure;
    }
    rng_status = PRNGTEST_Generate(result, sizeof rng_known_result, NULL, 0);
    if ((rng_status != SECSuccess) ||
        (PORT_Memcmp(result, rng_known_result,
                     sizeof rng_known_result) != 0)) {
        PRNGTEST_Uninstantiate();
        PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
        return SECFailure;
    }
    rng_status = PRNGTEST_Reseed(reseed_entropy, sizeof reseed_entropy,
                                 additional_input, sizeof additional_input);
    if (rng_status != SECSuccess) {
        /* Error set by PRNG_Reseed */
        PRNGTEST_Uninstantiate();
        return SECFailure;
    }
    rng_status = PRNGTEST_Generate(result, sizeof rng_reseed_result, NULL, 0);
    if ((rng_status != SECSuccess) ||
        (PORT_Memcmp(result, rng_reseed_result,
                     sizeof rng_reseed_result) != 0)) {
        PRNGTEST_Uninstantiate();
        PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
        return SECFailure;
    }
    /* This magic forces the reseed count to it's max count, so we can see if
     * PRNGTEST_Generate will actually when it reaches it's count */
    rng_status = PRNGTEST_Reseed(NULL, 0, NULL, 0);
    if (rng_status != SECSuccess) {
        PRNGTEST_Uninstantiate();
        /* Error set by PRNG_Reseed */
        return SECFailure;
    }
    /* This generate should now reseed */
    rng_status = PRNGTEST_Generate(result, sizeof rng_reseed_result, NULL, 0);
    if ((rng_status != SECSuccess) ||
        /* NOTE we fail if the result is equal to the no_reseed_result.
         * no_reseed_result is the value we would have gotten if we didn't
         * do an automatic reseed in PRNGTEST_Generate */
        (PORT_Memcmp(result, rng_no_reseed_result,
                     sizeof rng_no_reseed_result) == 0)) {
        PRNGTEST_Uninstantiate();
        PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
        return SECFailure;
    }
    /* make sure reseed fails when we don't supply enough entropy */
    rng_status = PRNGTEST_Reseed(reseed_entropy, 4, NULL, 0);
    if (rng_status == SECSuccess) {
        PRNGTEST_Uninstantiate();
        PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
        return SECFailure;
    }
    if (PORT_GetError() != SEC_ERROR_NEED_RANDOM) {
        PRNGTEST_Uninstantiate();
        PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
        return SECFailure;
    }
    rng_status = PRNGTEST_Uninstantiate();
    if (rng_status != SECSuccess) {
        /* Error set by PRNG_Uninstantiate */
        return rng_status;
    }
    /* make sure uninstantiate fails if the contest is not initiated (also tests
     * if the context was cleared in the previous Uninstantiate) */
    rng_status = PRNGTEST_Uninstantiate();
    if (rng_status == SECSuccess) {
        PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
        return SECFailure;
    }
    if (PORT_GetError() != SEC_ERROR_LIBRARY_FAILURE) {
        return rng_status;
    }

    return SECSuccess;
}
Beispiel #12
0
/*
** Update the global random number generator with more seeding
** material.
*/
SECStatus
RNG_RandomUpdate(const void *data, size_t bytes)
{
    SECStatus rv;

    /* Make sure our assumption that size_t is unsigned is true */
    PR_STATIC_ASSERT(((size_t)-1) > (size_t)1);

#if defined(NS_PTR_GT_32) || (defined(NSS_USE_64) && !defined(NS_PTR_LE_32))
    /*
     * NIST 800-90 requires us to verify our inputs. This value can
     * come from the application, so we need to make sure it's within the
     * spec. The spec says it must be less than 2^32 bytes (2^35 bits).
     * This can only happen if size_t is greater than 32 bits (i.e. on
     * most 64 bit platforms). The 90% case (perhaps 100% case), size_t
     * is less than or equal to 32 bits if the platform is not 64 bits, and
     * greater than 32 bits if it is a 64 bit platform. The corner
     * cases are handled with explicit defines NS_PTR_GT_32 and NS_PTR_LE_32.
     *
     * In general, neither NS_PTR_GT_32 nor NS_PTR_LE_32 will need to be
     * defined. If you trip over the next two size ASSERTS at compile time,
     * you will need to define them for your platform.
     *
     * if 'sizeof(size_t) > 4' is triggered it means that we were expecting
     *   sizeof(size_t) to be greater than 4, but it wasn't. Setting
     *   NS_PTR_LE_32 will correct that mistake.
     *
     * if 'sizeof(size_t) <= 4' is triggered, it means that we were expecting
     *   sizeof(size_t) to be less than or equal to 4, but it wasn't. Setting
     *   NS_PTR_GT_32 will correct that mistake.
     */

    PR_STATIC_ASSERT(sizeof(size_t) > 4);

    if (bytes > (size_t)PRNG_MAX_ADDITIONAL_BYTES) {
        bytes = PRNG_MAX_ADDITIONAL_BYTES;
    }
#else
    PR_STATIC_ASSERT(sizeof(size_t) <= 4);
#endif

    PZ_Lock(globalrng->lock);
    /* if we're passed more than our additionalDataCache, simply
     * call reseed with that data */
    if (bytes > sizeof(globalrng->additionalDataCache)) {
        rv = prng_reseed_test(globalrng, NULL, 0, data, (unsigned int)bytes);
        /* if we aren't going to fill or overflow the buffer, just cache it */
    } else if (bytes < ((sizeof globalrng->additionalDataCache) - globalrng->additionalAvail)) {
        PORT_Memcpy(globalrng->additionalDataCache + globalrng->additionalAvail,
                    data, bytes);
        globalrng->additionalAvail += (PRUint32)bytes;
        rv = SECSuccess;
    } else {
        /* we are going to fill or overflow the buffer. In this case we will
         * fill the entropy buffer, reseed with it, start a new buffer with the
         * remainder. We know the remainder will fit in the buffer because
         * we already handled the case where bytes > the size of the buffer.
         */
        size_t bufRemain = (sizeof globalrng->additionalDataCache) - globalrng->additionalAvail;
        /* fill the rest of the buffer */
        if (bufRemain) {
            PORT_Memcpy(globalrng->additionalDataCache + globalrng->additionalAvail,
                        data, bufRemain);
            data = ((unsigned char *)data) + bufRemain;
            bytes -= bufRemain;
        }
        /* reseed from buffer */
        rv = prng_reseed_test(globalrng, NULL, 0,
                              globalrng->additionalDataCache,
                              sizeof globalrng->additionalDataCache);

        /* copy the rest into the cache */
        PORT_Memcpy(globalrng->additionalDataCache, data, bytes);
        globalrng->additionalAvail = (PRUint32)bytes;
    }

    PZ_Unlock(globalrng->lock);
    return rv;
}