diff options
author | Mathias Agopian <mathias@google.com> | 2013-05-06 20:20:50 -0700 |
---|---|---|
committer | Mathias Agopian <mathias@google.com> | 2013-05-07 18:28:11 -0700 |
commit | 002e1e58dfe19dd3e49a59c6827cbf51573941a2 (patch) | |
tree | 6dc444d7f05aa0512e3c97344d86ee0264daf869 /libs/binder | |
parent | b4f1a027cbadd4cd07341f60f859ae34643b68ae (diff) | |
download | frameworks_native-002e1e58dfe19dd3e49a59c6827cbf51573941a2.zip frameworks_native-002e1e58dfe19dd3e49a59c6827cbf51573941a2.tar.gz frameworks_native-002e1e58dfe19dd3e49a59c6827cbf51573941a2.tar.bz2 |
libutils clean-up
Change-Id: I6ff4cfc736751de2912c697f954e45e275f2d386
Diffstat (limited to 'libs/binder')
-rw-r--r-- | libs/binder/Android.mk | 5 | ||||
-rw-r--r-- | libs/binder/BufferedTextOutput.cpp | 279 | ||||
-rw-r--r-- | libs/binder/Debug.cpp | 304 | ||||
-rw-r--r-- | libs/binder/IPCThreadState.cpp | 3 | ||||
-rw-r--r-- | libs/binder/Parcel.cpp | 5 | ||||
-rw-r--r-- | libs/binder/Static.cpp | 54 | ||||
-rw-r--r-- | libs/binder/TextOutput.cpp | 154 |
7 files changed, 796 insertions, 8 deletions
diff --git a/libs/binder/Android.mk b/libs/binder/Android.mk index 994d3db..4c8820e 100644 --- a/libs/binder/Android.mk +++ b/libs/binder/Android.mk @@ -17,6 +17,8 @@ sources := \ AppOpsManager.cpp \ Binder.cpp \ BpBinder.cpp \ + BufferedTextOutput.cpp \ + Debug.cpp \ IAppOpsCallback.cpp \ IAppOpsService.cpp \ IInterface.cpp \ @@ -30,7 +32,8 @@ sources := \ Parcel.cpp \ PermissionCache.cpp \ ProcessState.cpp \ - Static.cpp + Static.cpp \ + TextOutput.cpp \ LOCAL_PATH:= $(call my-dir) diff --git a/libs/binder/BufferedTextOutput.cpp b/libs/binder/BufferedTextOutput.cpp new file mode 100644 index 0000000..2d493c1 --- /dev/null +++ b/libs/binder/BufferedTextOutput.cpp @@ -0,0 +1,279 @@ +/* + * Copyright (C) 2006 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include <binder/BufferedTextOutput.h> +#include <binder/Debug.h> + +#include <utils/Atomic.h> +#include <utils/Log.h> +#include <utils/RefBase.h> +#include <utils/Vector.h> +#include <cutils/threads.h> + +#include <private/binder/Static.h> + +#include <stdio.h> +#include <stdlib.h> + +// --------------------------------------------------------------------------- + +namespace android { + +struct BufferedTextOutput::BufferState : public RefBase +{ + BufferState(int32_t _seq) + : seq(_seq) + , buffer(NULL) + , bufferPos(0) + , bufferSize(0) + , atFront(true) + , indent(0) + , bundle(0) { + } + ~BufferState() { + free(buffer); + } + + status_t append(const char* txt, size_t len) { + if ((len+bufferPos) > bufferSize) { + void* b = realloc(buffer, ((len+bufferPos)*3)/2); + if (!b) return NO_MEMORY; + buffer = (char*)b; + } + memcpy(buffer+bufferPos, txt, len); + bufferPos += len; + return NO_ERROR; + } + + void restart() { + bufferPos = 0; + atFront = true; + if (bufferSize > 256) { + void* b = realloc(buffer, 256); + if (b) { + buffer = (char*)b; + bufferSize = 256; + } + } + } + + const int32_t seq; + char* buffer; + size_t bufferPos; + size_t bufferSize; + bool atFront; + int32_t indent; + int32_t bundle; +}; + +struct BufferedTextOutput::ThreadState +{ + Vector<sp<BufferedTextOutput::BufferState> > states; +}; + +static mutex_t gMutex; + +static thread_store_t tls; + +BufferedTextOutput::ThreadState* BufferedTextOutput::getThreadState() +{ + ThreadState* ts = (ThreadState*) thread_store_get( &tls ); + if (ts) return ts; + ts = new ThreadState; + thread_store_set( &tls, ts, threadDestructor ); + return ts; +} + +void BufferedTextOutput::threadDestructor(void *st) +{ + delete ((ThreadState*)st); +} + +static volatile int32_t gSequence = 0; + +static volatile int32_t gFreeBufferIndex = -1; + +static int32_t allocBufferIndex() +{ + int32_t res = -1; + + mutex_lock(&gMutex); + + if (gFreeBufferIndex >= 0) { + res = gFreeBufferIndex; + gFreeBufferIndex = gTextBuffers[res]; + gTextBuffers.editItemAt(res) = -1; + + } else { + res = gTextBuffers.size(); + gTextBuffers.add(-1); + } + + mutex_unlock(&gMutex); + + return res; +} + +static void freeBufferIndex(int32_t idx) +{ + mutex_lock(&gMutex); + gTextBuffers.editItemAt(idx) = gFreeBufferIndex; + gFreeBufferIndex = idx; + mutex_unlock(&gMutex); +} + +// --------------------------------------------------------------------------- + +BufferedTextOutput::BufferedTextOutput(uint32_t flags) + : mFlags(flags) + , mSeq(android_atomic_inc(&gSequence)) + , mIndex(allocBufferIndex()) +{ + mGlobalState = new BufferState(mSeq); + if (mGlobalState) mGlobalState->incStrong(this); +} + +BufferedTextOutput::~BufferedTextOutput() +{ + if (mGlobalState) mGlobalState->decStrong(this); + freeBufferIndex(mIndex); +} + +status_t BufferedTextOutput::print(const char* txt, size_t len) +{ + //printf("BufferedTextOutput: printing %d\n", len); + + AutoMutex _l(mLock); + BufferState* b = getBuffer(); + + const char* const end = txt+len; + + status_t err; + + while (txt < end) { + // Find the next line. + const char* first = txt; + while (txt < end && *txt != '\n') txt++; + + // Include this and all following empty lines. + while (txt < end && *txt == '\n') txt++; + + // Special cases for first data on a line. + if (b->atFront) { + if (b->indent > 0) { + // If this is the start of a line, add the indent. + const char* prefix = stringForIndent(b->indent); + err = b->append(prefix, strlen(prefix)); + if (err != NO_ERROR) return err; + + } else if (*(txt-1) == '\n' && !b->bundle) { + // Fast path: if we are not indenting or bundling, and + // have been given one or more complete lines, just write + // them out without going through the buffer. + + // Slurp up all of the lines. + const char* lastLine = txt+1; + while (txt < end) { + if (*txt++ == '\n') lastLine = txt; + } + struct iovec vec; + vec.iov_base = (void*)first; + vec.iov_len = lastLine-first; + //printf("Writing %d bytes of data!\n", vec.iov_len); + writeLines(vec, 1); + txt = lastLine; + continue; + } + } + + // Append the new text to the buffer. + err = b->append(first, txt-first); + if (err != NO_ERROR) return err; + b->atFront = *(txt-1) == '\n'; + + // If we have finished a line and are not bundling, write + // it out. + //printf("Buffer is now %d bytes\n", b->bufferPos); + if (b->atFront && !b->bundle) { + struct iovec vec; + vec.iov_base = b->buffer; + vec.iov_len = b->bufferPos; + //printf("Writing %d bytes of data!\n", vec.iov_len); + writeLines(vec, 1); + b->restart(); + } + } + + return NO_ERROR; +} + +void BufferedTextOutput::moveIndent(int delta) +{ + AutoMutex _l(mLock); + BufferState* b = getBuffer(); + b->indent += delta; + if (b->indent < 0) b->indent = 0; +} + +void BufferedTextOutput::pushBundle() +{ + AutoMutex _l(mLock); + BufferState* b = getBuffer(); + b->bundle++; +} + +void BufferedTextOutput::popBundle() +{ + AutoMutex _l(mLock); + BufferState* b = getBuffer(); + b->bundle--; + LOG_FATAL_IF(b->bundle < 0, + "TextOutput::popBundle() called more times than pushBundle()"); + if (b->bundle < 0) b->bundle = 0; + + if (b->bundle == 0) { + // Last bundle, write out data if it is complete. If it is not + // complete, don't write until the last line is done... this may + // or may not be the write thing to do, but it's the easiest. + if (b->bufferPos > 0 && b->atFront) { + struct iovec vec; + vec.iov_base = b->buffer; + vec.iov_len = b->bufferPos; + writeLines(vec, 1); + b->restart(); + } + } +} + +BufferedTextOutput::BufferState* BufferedTextOutput::getBuffer() const +{ + if ((mFlags&MULTITHREADED) != 0) { + ThreadState* ts = getThreadState(); + if (ts) { + while (ts->states.size() <= (size_t)mIndex) ts->states.add(NULL); + BufferState* bs = ts->states[mIndex].get(); + if (bs != NULL && bs->seq == mSeq) return bs; + + ts->states.editItemAt(mIndex) = new BufferState(mIndex); + bs = ts->states[mIndex].get(); + if (bs != NULL) return bs; + } + } + + return mGlobalState; +} + +}; // namespace android diff --git a/libs/binder/Debug.cpp b/libs/binder/Debug.cpp new file mode 100644 index 0000000..a8b6e83 --- /dev/null +++ b/libs/binder/Debug.cpp @@ -0,0 +1,304 @@ +/* + * Copyright (C) 2005 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include <binder/Debug.h> + +#include <utils/misc.h> + +#include <stdio.h> +#include <stdlib.h> +#include <ctype.h> + +namespace android { + +// --------------------------------------------------------------------- + +static const char indentStr[] = +" " +" "; + +const char* stringForIndent(int32_t indentLevel) +{ + ssize_t off = sizeof(indentStr)-1-(indentLevel*2); + return indentStr + (off < 0 ? 0 : off); +} + +// --------------------------------------------------------------------- + +static void defaultPrintFunc(void* cookie, const char* txt) +{ + printf("%s", txt); +} + +// --------------------------------------------------------------------- + +static inline int isident(int c) +{ + return isalnum(c) || c == '_'; +} + +static inline bool isasciitype(char c) +{ + if( c >= ' ' && c < 127 && c != '\'' && c != '\\' ) return true; + return false; +} + +static inline char makehexdigit(uint32_t val) +{ + return "0123456789abcdef"[val&0xF]; +} + +static char* appendhexnum(uint32_t val, char* out) +{ + for( int32_t i=28; i>=0; i-=4 ) { + *out++ = makehexdigit( val>>i ); + } + *out = 0; + return out; +} + +static char* appendcharornum(char c, char* out, bool skipzero = true) +{ + if (skipzero && c == 0) return out; + + if (isasciitype(c)) { + *out++ = c; + return out; + } + + *out++ = '\\'; + *out++ = 'x'; + *out++ = makehexdigit(c>>4); + *out++ = makehexdigit(c); + return out; +} + +static char* typetostring(uint32_t type, char* out, + bool fullContext = true, + bool strict = false) +{ + char* pos = out; + char c[4]; + c[0] = (char)((type>>24)&0xFF); + c[1] = (char)((type>>16)&0xFF); + c[2] = (char)((type>>8)&0xFF); + c[3] = (char)(type&0xFF); + bool valid; + if( !strict ) { + // now even less strict! + // valid = isasciitype(c[3]); + valid = true; + int32_t i = 0; + bool zero = true; + while (valid && i<3) { + if (c[i] == 0) { + if (!zero) valid = false; + } else { + zero = false; + //if (!isasciitype(c[i])) valid = false; + } + i++; + } + // if all zeros, not a valid type code. + if (zero) valid = false; + } else { + valid = isident(c[3]) ? true : false; + int32_t i = 0; + bool zero = true; + while (valid && i<3) { + if (c[i] == 0) { + if (!zero) valid = false; + } else { + zero = false; + if (!isident(c[i])) valid = false; + } + i++; + } + } + if( valid && (!fullContext || c[0] != '0' || c[1] != 'x') ) { + if( fullContext ) *pos++ = '\''; + pos = appendcharornum(c[0], pos); + pos = appendcharornum(c[1], pos); + pos = appendcharornum(c[2], pos); + pos = appendcharornum(c[3], pos); + if( fullContext ) *pos++ = '\''; + *pos = 0; + return pos; + } + + if( fullContext ) { + *pos++ = '0'; + *pos++ = 'x'; + } + return appendhexnum(type, pos); +} + +void printTypeCode(uint32_t typeCode, debugPrintFunc func, void* cookie) +{ + char buffer[32]; + char* end = typetostring(typeCode, buffer); + *end = 0; + func ? (*func)(cookie, buffer) : defaultPrintFunc(cookie, buffer); +} + +void printHexData(int32_t indent, const void *buf, size_t length, + size_t bytesPerLine, int32_t singleLineBytesCutoff, + size_t alignment, bool cStyle, + debugPrintFunc func, void* cookie) +{ + if (alignment == 0) { + if (bytesPerLine >= 16) alignment = 4; + else if (bytesPerLine >= 8) alignment = 2; + else alignment = 1; + } + if (func == NULL) func = defaultPrintFunc; + + size_t offset; + + unsigned char *pos = (unsigned char *)buf; + + if (pos == NULL) { + if (singleLineBytesCutoff < 0) func(cookie, "\n"); + func(cookie, "(NULL)"); + return; + } + + if (length == 0) { + if (singleLineBytesCutoff < 0) func(cookie, "\n"); + func(cookie, "(empty)"); + return; + } + + if ((int32_t)length < 0) { + if (singleLineBytesCutoff < 0) func(cookie, "\n"); + char buf[64]; + sprintf(buf, "(bad length: %zu)", length); + func(cookie, buf); + return; + } + + char buffer[256]; + static const size_t maxBytesPerLine = (sizeof(buffer)-1-11-4)/(3+1); + + if (bytesPerLine > maxBytesPerLine) bytesPerLine = maxBytesPerLine; + + const bool oneLine = (int32_t)length <= singleLineBytesCutoff; + bool newLine = false; + if (cStyle) { + indent++; + func(cookie, "{\n"); + newLine = true; + } else if (!oneLine) { + func(cookie, "\n"); + newLine = true; + } + + for (offset = 0; ; offset += bytesPerLine, pos += bytesPerLine) { + long remain = length; + + char* c = buffer; + if (!oneLine && !cStyle) { + sprintf(c, "0x%08x: ", (int)offset); + c += 12; + } + + size_t index; + size_t word; + + for (word = 0; word < bytesPerLine; ) { + +#ifdef HAVE_LITTLE_ENDIAN + const size_t startIndex = word+(alignment-(alignment?1:0)); + const ssize_t dir = -1; +#else + const size_t startIndex = word; + const ssize_t dir = 1; +#endif + + for (index = 0; index < alignment || (alignment == 0 && index < bytesPerLine); index++) { + + if (!cStyle) { + if (index == 0 && word > 0 && alignment > 0) { + *c++ = ' '; + } + + if (remain-- > 0) { + const unsigned char val = *(pos+startIndex+(index*dir)); + *c++ = makehexdigit(val>>4); + *c++ = makehexdigit(val); + } else if (!oneLine) { + *c++ = ' '; + *c++ = ' '; + } + } else { + if (remain > 0) { + if (index == 0 && word > 0) { + *c++ = ','; + *c++ = ' '; + } + if (index == 0) { + *c++ = '0'; + *c++ = 'x'; + } + const unsigned char val = *(pos+startIndex+(index*dir)); + *c++ = makehexdigit(val>>4); + *c++ = makehexdigit(val); + remain--; + } + } + } + + word += index; + } + + if (!cStyle) { + remain = length; + *c++ = ' '; + *c++ = '\''; + for (index = 0; index < bytesPerLine; index++) { + + if (remain-- > 0) { + const unsigned char val = pos[index]; + *c++ = (val >= ' ' && val < 127) ? val : '.'; + } else if (!oneLine) { + *c++ = ' '; + } + } + + *c++ = '\''; + if (length > bytesPerLine) *c++ = '\n'; + } else { + if (remain > 0) *c++ = ','; + *c++ = '\n'; + } + + if (newLine && indent) func(cookie, stringForIndent(indent)); + *c = 0; + func(cookie, buffer); + newLine = true; + + if (length <= bytesPerLine) break; + length -= bytesPerLine; + } + + if (cStyle) { + if (indent > 0) func(cookie, stringForIndent(indent-1)); + func(cookie, "};"); + } +} + +}; // namespace android + diff --git a/libs/binder/IPCThreadState.cpp b/libs/binder/IPCThreadState.cpp index 6e83faa..2780d9a 100644 --- a/libs/binder/IPCThreadState.cpp +++ b/libs/binder/IPCThreadState.cpp @@ -20,10 +20,11 @@ #include <binder/Binder.h> #include <binder/BpBinder.h> +#include <binder/TextOutput.h> + #include <cutils/sched_policy.h> #include <utils/Debug.h> #include <utils/Log.h> -#include <utils/TextOutput.h> #include <utils/threads.h> #include <private/binder/binder_module.h> diff --git a/libs/binder/Parcel.cpp b/libs/binder/Parcel.cpp index 8f7f7e7..aa19d17 100644 --- a/libs/binder/Parcel.cpp +++ b/libs/binder/Parcel.cpp @@ -22,12 +22,13 @@ #include <binder/IPCThreadState.h> #include <binder/Binder.h> #include <binder/BpBinder.h> -#include <utils/Debug.h> #include <binder/ProcessState.h> +#include <binder/TextOutput.h> + +#include <utils/Debug.h> #include <utils/Log.h> #include <utils/String8.h> #include <utils/String16.h> -#include <utils/TextOutput.h> #include <utils/misc.h> #include <utils/Flattenable.h> #include <cutils/ashmem.h> diff --git a/libs/binder/Static.cpp b/libs/binder/Static.cpp index 12b0308..2062692 100644 --- a/libs/binder/Static.cpp +++ b/libs/binder/Static.cpp @@ -19,30 +19,76 @@ #include <private/binder/Static.h> +#include <binder/BufferedTextOutput.h> #include <binder/IPCThreadState.h> #include <utils/Log.h> namespace android { +// ------------ Text output streams + +Vector<int32_t> gTextBuffers; + +class LogTextOutput : public BufferedTextOutput +{ +public: + LogTextOutput() : BufferedTextOutput(MULTITHREADED) { } + virtual ~LogTextOutput() { }; + +protected: + virtual status_t writeLines(const struct iovec& vec, size_t N) + { + //android_writevLog(&vec, N); <-- this is now a no-op + if (N != 1) ALOGI("WARNING: writeLines N=%zu\n", N); + ALOGI("%.*s", (int)vec.iov_len, (const char*) vec.iov_base); + return NO_ERROR; + } +}; + +class FdTextOutput : public BufferedTextOutput +{ +public: + FdTextOutput(int fd) : BufferedTextOutput(MULTITHREADED), mFD(fd) { } + virtual ~FdTextOutput() { }; + +protected: + virtual status_t writeLines(const struct iovec& vec, size_t N) + { + writev(mFD, &vec, N); + return NO_ERROR; + } + +private: + int mFD; +}; + +static LogTextOutput gLogTextOutput; +static FdTextOutput gStdoutTextOutput(STDOUT_FILENO); +static FdTextOutput gStderrTextOutput(STDERR_FILENO); + +TextOutput& alog(gLogTextOutput); +TextOutput& aout(gStdoutTextOutput); +TextOutput& aerr(gStderrTextOutput); + // ------------ ProcessState.cpp Mutex gProcessMutex; sp<ProcessState> gProcess; -class LibUtilsIPCtStatics +class LibBinderIPCtStatics { public: - LibUtilsIPCtStatics() + LibBinderIPCtStatics() { } - ~LibUtilsIPCtStatics() + ~LibBinderIPCtStatics() { IPCThreadState::shutdown(); } }; -static LibUtilsIPCtStatics gIPCStatics; +static LibBinderIPCtStatics gIPCStatics; // ------------ ServiceManager.cpp diff --git a/libs/binder/TextOutput.cpp b/libs/binder/TextOutput.cpp new file mode 100644 index 0000000..9637334 --- /dev/null +++ b/libs/binder/TextOutput.cpp @@ -0,0 +1,154 @@ +/* + * Copyright (C) 2005 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include <binder/TextOutput.h> + +#include <binder/Debug.h> + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +namespace android { + +// --------------------------------------------------------------------------- + +TextOutput::TextOutput() { +} + +TextOutput::~TextOutput() { +} + +// --------------------------------------------------------------------------- + +TextOutput& operator<<(TextOutput& to, bool val) +{ + if (val) to.print("true", 4); + else to.print("false", 5); + return to; +} + +TextOutput& operator<<(TextOutput& to, int val) +{ + char buf[16]; + sprintf(buf, "%d", val); + to.print(buf, strlen(buf)); + return to; +} + +TextOutput& operator<<(TextOutput& to, long val) +{ + char buf[16]; + sprintf(buf, "%ld", val); + to.print(buf, strlen(buf)); + return to; +} + +TextOutput& operator<<(TextOutput& to, unsigned int val) +{ + char buf[16]; + sprintf(buf, "%u", val); + to.print(buf, strlen(buf)); + return to; +} + +TextOutput& operator<<(TextOutput& to, unsigned long val) +{ + char buf[16]; + sprintf(buf, "%lu", val); + to.print(buf, strlen(buf)); + return to; +} + +TextOutput& operator<<(TextOutput& to, long long val) +{ + char buf[32]; + sprintf(buf, "%Ld", val); + to.print(buf, strlen(buf)); + return to; +} + +TextOutput& operator<<(TextOutput& to, unsigned long long val) +{ + char buf[32]; + sprintf(buf, "%Lu", val); + to.print(buf, strlen(buf)); + return to; +} + +static TextOutput& print_float(TextOutput& to, double value) +{ + char buf[64]; + sprintf(buf, "%g", value); + if( !strchr(buf, '.') && !strchr(buf, 'e') && + !strchr(buf, 'E') ) { + strncat(buf, ".0", sizeof(buf)-1); + } + to.print(buf, strlen(buf)); + return to; +} + +TextOutput& operator<<(TextOutput& to, float val) +{ + return print_float(to,val); +} + +TextOutput& operator<<(TextOutput& to, double val) +{ + return print_float(to,val); +} + +TextOutput& operator<<(TextOutput& to, const void* val) +{ + char buf[16]; + sprintf(buf, "%p", val); + to.print(buf, strlen(buf)); + return to; +} + +static void textOutputPrinter(void* cookie, const char* txt) +{ + ((TextOutput*)cookie)->print(txt, strlen(txt)); +} + +TextOutput& operator<<(TextOutput& to, const TypeCode& val) +{ + printTypeCode(val.typeCode(), textOutputPrinter, (void*)&to); + return to; +} + +HexDump::HexDump(const void *buf, size_t size, size_t bytesPerLine) + : mBuffer(buf) + , mSize(size) + , mBytesPerLine(bytesPerLine) + , mSingleLineCutoff(16) + , mAlignment(4) + , mCArrayStyle(false) +{ + if (bytesPerLine >= 16) mAlignment = 4; + else if (bytesPerLine >= 8) mAlignment = 2; + else mAlignment = 1; +} + +TextOutput& operator<<(TextOutput& to, const HexDump& val) +{ + printHexData(0, val.buffer(), val.size(), val.bytesPerLine(), + val.singleLineCutoff(), val.alignment(), val.carrayStyle(), + textOutputPrinter, (void*)&to); + return to; +} + +}; // namespace android |