resources/src/main/java/org/robolectric/res/android/ResStringPool.java
public int setTo(ByteBuffer buf, int offset, int size, boolean copyData) {
    if (!isTruthy(buf) || !isTruthy(size)) {
      return (mError=BAD_TYPE);
    }

    uninit();

    // The chunk must be at least the size of the string pool header.
    if (size < ResStringPool_header.SIZEOF) {
      ALOGW("Bad string block: data size %zu is too small to be a string block", size);
      return (mError=BAD_TYPE);
    }

    // The data is at least as big as a ResChunk_header, so we can safely validate the other
    // header fields.
    // `data + size` is safe because the source of `size` comes from the kernel/filesystem.
    if (validate_chunk(new ResChunk_header(buf, offset), ResStringPool_header.SIZEOF,
        size,
        "ResStringPool_header") != NO_ERROR) {
      ALOGW("Bad string block: malformed block dimensions");
      return (mError=BAD_TYPE);
    }

//    final boolean notDeviceEndian = htods((short) 0xf0) != 0xf0;
//
//    if (copyData || notDeviceEndian) {
//      mOwnedData = data;
//      if (mOwnedData == null) {
//        return (mError=NO_MEMORY);
//      }
////      memcpy(mOwnedData, data, size);
//      data = mOwnedData;
//    }

    // The size has been checked, so it is safe to read the data in the ResStringPool_header
    // data structure.
    mHeader = new ResStringPool_header(buf, offset);

//    if (notDeviceEndian) {
//      ResStringPool_header h = final_cast<ResStringPool_header*>(mHeader);
//      h.header.headerSize = dtohs(mHeader.header.headerSize);
//      h.header.type = dtohs(mHeader.header.type);
//      h.header.size = dtohl(mHeader.header.size);
//      h.stringCount = dtohl(mHeader.stringCount);
//      h.styleCount = dtohl(mHeader.styleCount);
//      h.flags = dtohl(mHeader.flags);
//      h.stringsStart = dtohl(mHeader.stringsStart);
//      h.stylesStart = dtohl(mHeader.stylesStart);
//    }

    if (mHeader.header.headerSize > mHeader.header.size
        || mHeader.header.size > size) {
      ALOGW("Bad string block: header size %d or total size %d is larger than data size %d\n",
          (int)mHeader.header.headerSize, (int)mHeader.header.size, (int)size);
      return (mError=BAD_TYPE);
    }
    mSize = mHeader.header.size;
    mEntries = new IntArray(mHeader.myBuf(), mHeader.myOffset() + mHeader.header.headerSize);

    if (mHeader.stringCount > 0) {
      if ((mHeader.stringCount*4 /*sizeof(uint32_t)*/ < mHeader.stringCount)  // uint32 overflow?
          || (mHeader.header.headerSize+(mHeader.stringCount*4 /*sizeof(uint32_t)*/))
          > size) {
        ALOGW("Bad string block: entry of %d items extends past data size %d\n",
            (int)(mHeader.header.headerSize+(mHeader.stringCount*4/*sizeof(uint32_t)*/)),
            (int)size);
        return (mError=BAD_TYPE);
      }

      int charSize;
      if (isTruthy(mHeader.flags & ResStringPool_header.UTF8_FLAG)) {
        charSize = 1 /*sizeof(uint8_t)*/;
      } else {
        charSize = 2 /*sizeof(uint16_t)*/;
      }

      // There should be at least space for the smallest string
      // (2 bytes length, null terminator).
      if (mHeader.stringsStart >= (mSize - 2 /*sizeof(uint16_t)*/)) {
        ALOGW("Bad string block: string pool starts at %d, after total size %d\n",
            (int)mHeader.stringsStart, (int)mHeader.header.size);
        return (mError=BAD_TYPE);
      }

      mStrings = mHeader.stringsStart;

      if (mHeader.styleCount == 0) {
        mStringPoolSize = (mSize - mHeader.stringsStart) / charSize;
      } else {
        // check invariant: styles starts before end of data
        if (mHeader.stylesStart >= (mSize - 2 /*sizeof(uint16_t)*/)) {
          ALOGW("Bad style block: style block starts at %d past data size of %d\n",
              (int)mHeader.stylesStart, (int)mHeader.header.size);
          return (mError=BAD_TYPE);
        }
        // check invariant: styles follow the strings
        if (mHeader.stylesStart <= mHeader.stringsStart) {
          ALOGW("Bad style block: style block starts at %d, before strings at %d\n",
              (int)mHeader.stylesStart, (int)mHeader.stringsStart);
          return (mError=BAD_TYPE);
        }
        mStringPoolSize =
            (mHeader.stylesStart-mHeader.stringsStart)/charSize;
      }

      // check invariant: stringCount > 0 requires a string pool to exist
      if (mStringPoolSize == 0) {
        ALOGW("Bad string block: stringCount is %d but pool size is 0\n", (int)mHeader.stringCount);
        return (mError=BAD_TYPE);
      }

      //      if (notDeviceEndian) {
      //        int i;
      //        uint32_t* e = final_cast<uint32_t*>(mEntries);
      //        for (i=0; i<mHeader.stringCount; i++) {
      //          e[i] = dtohl(mEntries[i]);
      //        }
      //        if (!(mHeader.flags&ResStringPool_header::UTF8_FLAG)) {
      //                final uint16_t* strings = (final uint16_t*)mStrings;
      //          uint16_t* s = final_cast<uint16_t*>(strings);
      //          for (i=0; i<mStringPoolSize; i++) {
      //            s[i] = dtohs(strings[i]);
      //          }
      //        }
      //      }

      //      if ((mHeader->flags&ResStringPool_header::UTF8_FLAG &&
      //          ((uint8_t*)mStrings)[mStringPoolSize-1] != 0) ||
      //      (!(mHeader->flags&ResStringPool_header::UTF8_FLAG) &&
      //          ((uint16_t*)mStrings)[mStringPoolSize-1] != 0)) {

      if ((isTruthy(mHeader.flags & ResStringPool_header.UTF8_FLAG)
              && (mHeader.getByte(mStrings + mStringPoolSize - 1) != 0))
          || (!isTruthy(mHeader.flags & ResStringPool_header.UTF8_FLAG)
              && (mHeader.getShort(mStrings + mStringPoolSize * 2 - 2) != 0))) {
        ALOGW("Bad string block: last string is not 0-terminated\n");
        return (mError=BAD_TYPE);
      }
    } else {
      mStrings = -1;
      mStringPoolSize = 0;
    }

    if (mHeader.styleCount > 0) {
      mEntryStyles = new IntArray(mEntries.myBuf(), mEntries.myOffset() + mHeader.stringCount * SIZEOF_INT);
      // invariant: integer overflow in calculating mEntryStyles
      if (mEntryStyles.myOffset() < mEntries.myOffset()) {
        ALOGW("Bad string block: integer overflow finding styles\n");
        return (mError=BAD_TYPE);
      }

//      if (((const uint8_t*)mEntryStyles-(const uint8_t*)mHeader) > (int)size) {
      if ((mEntryStyles.myOffset() - mHeader.myOffset()) > (int)size) {
        ALOGW("Bad string block: entry of %d styles extends past data size %d\n",
            (int)(mEntryStyles.myOffset()),
        (int)size);
        return (mError=BAD_TYPE);
      }
      mStyles = mHeader.stylesStart;
      if (mHeader.stylesStart >= mHeader.header.size) {
        ALOGW("Bad string block: style pool starts %d, after total size %d\n",
            (int)mHeader.stylesStart, (int)mHeader.header.size);
        return (mError=BAD_TYPE);
      }
      mStylePoolSize =
          (mHeader.header.size-mHeader.stylesStart) /* / sizeof(uint32_t)*/;

//      if (notDeviceEndian) {
//        size_t i;
//        uint32_t* e = final_cast<uint32_t*>(mEntryStyles);
//        for (i=0; i<mHeader.styleCount; i++) {
//          e[i] = dtohl(mEntryStyles[i]);
//        }
//        uint32_t* s = final_cast<uint32_t*>(mStyles);
//        for (i=0; i<mStylePoolSize; i++) {
//          s[i] = dtohl(mStyles[i]);
//        }
//      }

//        final ResStringPool_span endSpan = {
//          { htodl(ResStringPool_span.END) },
//          htodl(ResStringPool_span.END), htodl(ResStringPool_span.END)
//      };
//      if (memcmp(&mStyles[mStylePoolSize-(sizeof(endSpan)/sizeof(uint32_t))],
//                   &endSpan, sizeof(endSpan)) != 0) {
      ResStringPool_span endSpan = new ResStringPool_span(buf,
          mHeader.myOffset() + mStyles + (mStylePoolSize - ResStringPool_span.SIZEOF /* / 4 */));
      if (!endSpan.isEnd()) {
        ALOGW("Bad string block: last style is not 0xFFFFFFFF-terminated\n");
        return (mError=BAD_TYPE);
      }
    } else {
      mEntryStyles = null;
      mStyles = 0;
      mStylePoolSize = 0;
    }

    return (mError=NO_ERROR);
  }
public int setTo(ByteBuffer buf, int offset, int size, boolean copyData) {
    if (!isTruthy(buf) || !isTruthy(size)) {
      return (mError=BAD_TYPE);
    }

    uninit();

    // The chunk must be at least the size of the string pool header.
    if (size < ResStringPool_header.SIZEOF) {
      ALOGW("Bad string block: data size %zu is too small to be a string block", size);
      return (mError=BAD_TYPE);
    }

    // The data is at least as big as a ResChunk_header, so we can safely validate the other
    // header fields.
    // `data + size` is safe because the source of `size` comes from the kernel/filesystem.
    if (validate_chunk(new ResChunk_header(buf, offset), ResStringPool_header.SIZEOF,
        size,
        "ResStringPool_header") != NO_ERROR) {
      ALOGW("Bad string block: malformed block dimensions");
      return (mError=BAD_TYPE);
    }

//    final boolean notDeviceEndian = htods((short) 0xf0) != 0xf0;
//
//    if (copyData || notDeviceEndian) {
//      mOwnedData = data;
//      if (mOwnedData == null) {
//        return (mError=NO_MEMORY);
//      }
////      memcpy(mOwnedData, data, size);
//      data = mOwnedData;
//    }

    // The size has been checked, so it is safe to read the data in the ResStringPool_header
    // data structure.
    mHeader = new ResStringPool_header(buf, offset);

//    if (notDeviceEndian) {
//      ResStringPool_header h = final_cast<ResStringPool_header*>(mHeader);
//      h.header.headerSize = dtohs(mHeader.header.headerSize);
//      h.header.type = dtohs(mHeader.header.type);
//      h.header.size = dtohl(mHeader.header.size);
//      h.stringCount = dtohl(mHeader.stringCount);
//      h.styleCount = dtohl(mHeader.styleCount);
//      h.flags = dtohl(mHeader.flags);
//      h.stringsStart = dtohl(mHeader.stringsStart);
//      h.stylesStart = dtohl(mHeader.stylesStart);
//    }

    if (mHeader.header.headerSize > mHeader.header.size
        || mHeader.header.size > size) {
      ALOGW("Bad string block: header size %d or total size %d is larger than data size %d\n",
          (int)mHeader.header.headerSize, (int)mHeader.header.size, (int)size);
      return (mError=BAD_TYPE);
    }
    mSize = mHeader.header.size;
    mEntries = new IntArray(mHeader.myBuf(), mHeader.myOffset() + mHeader.header.headerSize);

    if (mHeader.stringCount > 0) {
      if ((mHeader.stringCount*4 /*sizeof(uint32_t)*/ < mHeader.stringCount)  // uint32 overflow?
          || (mHeader.header.headerSize+(mHeader.stringCount*4 /*sizeof(uint32_t)*/))
          > size) {
        ALOGW("Bad string block: entry of %d items extends past data size %d\n",
            (int)(mHeader.header.headerSize+(mHeader.stringCount*4/*sizeof(uint32_t)*/)),
            (int)size);
        return (mError=BAD_TYPE);
      }

      int charSize;
      if (isTruthy(mHeader.flags & ResStringPool_header.UTF8_FLAG)) {
        charSize = 1 /*sizeof(uint8_t)*/;
      } else {
        charSize = 2 /*sizeof(uint16_t)*/;
      }

      // There should be at least space for the smallest string
      // (2 bytes length, null terminator).
      if (mHeader.stringsStart >= (mSize - 2 /*sizeof(uint16_t)*/)) {
        ALOGW("Bad string block: string pool starts at %d, after total size %d\n",
            (int)mHeader.stringsStart, (int)mHeader.header.size);
        return (mError=BAD_TYPE);
      }

      mStrings = mHeader.stringsStart;

      if (mHeader.styleCount == 0) {
        mStringPoolSize = (mSize - mHeader.stringsStart) / charSize;
      } else {
        // check invariant: styles starts before end of data
        if (mHeader.stylesStart >= (mSize - 2 /*sizeof(uint16_t)*/)) {
          ALOGW("Bad style block: style block starts at %d past data size of %d\n",
              (int)mHeader.stylesStart, (int)mHeader.header.size);
          return (mError=BAD_TYPE);
        }
        // check invariant: styles follow the strings
        if (mHeader.stylesStart <= mHeader.stringsStart) {
          ALOGW("Bad style block: style block starts at %d, before strings at %d\n",
              (int)mHeader.stylesStart, (int)mHeader.stringsStart);
          return (mError=BAD_TYPE);
        }
        mStringPoolSize =
            (mHeader.stylesStart-mHeader.stringsStart)/charSize;
      }

      // check invariant: stringCount > 0 requires a string pool to exist
      if (mStringPoolSize == 0) {
        ALOGW("Bad string block: stringCount is %d but pool size is 0\n", (int)mHeader.stringCount);
        return (mError=BAD_TYPE);
      }

      //      if (notDeviceEndian) {
      //        int i;
      //        uint32_t* e = final_cast<uint32_t*>(mEntries);
      //        for (i=0; i<mHeader.stringCount; i++) {
      //          e[i] = dtohl(mEntries[i]);
      //        }
      //        if (!(mHeader.flags&ResStringPool_header::UTF8_FLAG)) {
      //                final uint16_t* strings = (final uint16_t*)mStrings;
      //          uint16_t* s = final_cast<uint16_t*>(strings);
      //          for (i=0; i<mStringPoolSize; i++) {
      //            s[i] = dtohs(strings[i]);
      //          }
      //        }
      //      }

      //      if ((mHeader->flags&ResStringPool_header::UTF8_FLAG &&
      //          ((uint8_t*)mStrings)[mStringPoolSize-1] != 0) ||
      //      (!(mHeader->flags&ResStringPool_header::UTF8_FLAG) &&
      //          ((uint16_t*)mStrings)[mStringPoolSize-1] != 0)) {

      if ((isTruthy(mHeader.flags & ResStringPool_header.UTF8_FLAG)
              && (mHeader.getByte(mStrings + mStringPoolSize - 1) != 0))
          || (!isTruthy(mHeader.flags & ResStringPool_header.UTF8_FLAG)
              && (mHeader.getShort(mStrings + mStringPoolSize * 2 - 2) != 0))) {
        ALOGW("Bad string block: last string is not 0-terminated\n");
        return (mError=BAD_TYPE);
      }
    } else {
      mStrings = -1;
      mStringPoolSize = 0;
    }

    if (mHeader.styleCount > 0) {
      mEntryStyles = new IntArray(mEntries.myBuf(), mEntries.myOffset() + mHeader.stringCount * SIZEOF_INT);
      // invariant: integer overflow in calculating mEntryStyles
      if (mEntryStyles.myOffset() < mEntries.myOffset()) {
        ALOGW("Bad string block: integer overflow finding styles\n");
        return (mError=BAD_TYPE);
      }

//      if (((const uint8_t*)mEntryStyles-(const uint8_t*)mHeader) > (int)size) {
      if ((mEntryStyles.myOffset() - mHeader.myOffset()) > (int)size) {
        ALOGW("Bad string block: entry of %d styles extends past data size %d\n",
            (int)(mEntryStyles.myOffset()),
        (int)size);
        return (mError=BAD_TYPE);
      }
      mStyles = mHeader.stylesStart;
      if (mHeader.stylesStart >= mHeader.header.size) {
        ALOGW("Bad string block: style pool starts %d, after total size %d\n",
            (int)mHeader.stylesStart, (int)mHeader.header.size);
        return (mError=BAD_TYPE);
      }
      mStylePoolSize =
          (mHeader.header.size-mHeader.stylesStart) /* / sizeof(uint32_t)*/;

//      if (notDeviceEndian) {
//        size_t i;
//        uint32_t* e = final_cast<uint32_t*>(mEntryStyles);
//        for (i=0; i<mHeader.styleCount; i++) {
//          e[i] = dtohl(mEntryStyles[i]);
//        }
//        uint32_t* s = final_cast<uint32_t*>(mStyles);
//        for (i=0; i<mStylePoolSize; i++) {
//          s[i] = dtohl(mStyles[i]);
//        }
//      }

//        final ResStringPool_span endSpan = {
//          { htodl(ResStringPool_span.END) },
//          htodl(ResStringPool_span.END), htodl(ResStringPool_span.END)
//      };
//      if (memcmp(&mStyles[mStylePoolSize-(sizeof(endSpan)/sizeof(uint32_t))],
//                   &endSpan, sizeof(endSpan)) != 0) {
      ResStringPool_span endSpan = new ResStringPool_span(buf,
          mHeader.myOffset() + mStyles + (mStylePoolSize - ResStringPool_span.SIZEOF /* / 4 */));
      if (!endSpan.isEnd()) {
        ALOGW("Bad string block: last style is not 0xFFFFFFFF-terminated\n");
        return (mError=BAD_TYPE);
      }
    } else {
      mEntryStyles = null;
      mStyles = 0;
      mStylePoolSize = 0;
    }

    return (mError=NO_ERROR);
  }
status_t setTo(const void* data, size_t size, bool copyData=false);