diff --git a/app/src/main/java/com/emanuelef/remote_capture/Utils.java b/app/src/main/java/com/emanuelef/remote_capture/Utils.java index 188b8431..90ef4c69 100644 --- a/app/src/main/java/com/emanuelef/remote_capture/Utils.java +++ b/app/src/main/java/com/emanuelef/remote_capture/Utils.java @@ -1125,4 +1125,8 @@ public class Utils { icon.setColorFilter(ContextCompat.getColor(context, color)); icon.setImageDrawable(ContextCompat.getDrawable(context, resid)); } + + public static boolean isPrintable(byte c) { + return ((c >= 32) && (c <= 126)) || (c == '\r') || (c == '\n') || (c == '\t'); + } } diff --git a/app/src/main/java/com/emanuelef/remote_capture/adapters/PayloadAdapter.java b/app/src/main/java/com/emanuelef/remote_capture/adapters/PayloadAdapter.java index 30179abf..186c807d 100644 --- a/app/src/main/java/com/emanuelef/remote_capture/adapters/PayloadAdapter.java +++ b/app/src/main/java/com/emanuelef/remote_capture/adapters/PayloadAdapter.java @@ -19,6 +19,7 @@ package com.emanuelef.remote_capture.adapters; +import android.annotation.SuppressLint; import android.content.Context; import android.util.Log; import android.view.LayoutInflater; @@ -63,6 +64,7 @@ public class PayloadAdapter extends RecyclerView.Adapter mChunks = new ArrayList<>(); private final HTTPReassembly mHttpReq; private final HTTPReassembly mHttpRes; + private boolean mShowAsPrintable; public PayloadAdapter(Context context, ConnectionDescriptor conn, ChunkType mode) { mLayoutInflater = (LayoutInflater)context.getSystemService(Context.LAYOUT_INFLATER_SERVICE); @@ -111,15 +113,13 @@ public class PayloadAdapter extends RecyclerView.Adapter 0) && mJustCreated) { + mShowAsPrintable = guessDisplayAsPrintable(); + mAdapter.setDisplayAsPrintableText(mShowAsPrintable); + mJustCreated = false; + } + refreshDisplayMode(); + } + + @Override + public boolean onOptionsItemSelected(@NonNull MenuItem item) { + int id = item.getItemId(); + + if(id == R.id.printable_text) { + mShowAsPrintable = true; + mAdapter.setDisplayAsPrintableText(true); + refreshDisplayMode(); + return true; + } else if(id == R.id.hexdump) { + mShowAsPrintable = false; + mAdapter.setDisplayAsPrintableText(false); + refreshDisplayMode(); + return true; + } + + return super.onOptionsItemSelected(item); + } + + private boolean guessDisplayAsPrintable() { + // try to determine the best mode based on the current payload + if(mConn.getNumPayloadChunks() == 0) + return mConn.l7proto.equals("HTTPS"); + + PayloadChunk firstChunk = mConn.getPayloadChunk(0); + if(firstChunk.type == PayloadChunk.ChunkType.HTTP) + return true; + + // guess based on the actual data + int maxLen = Math.min(firstChunk.payload.length, 16); + for(int i=0; i mCurChunks) { mAdapter.handleChunksAdded(mConn.getNumPayloadChunks()); mCurChunks = mConn.getNumPayloadChunks(); diff --git a/app/src/main/res/drawable/ic_short_text.xml b/app/src/main/res/drawable/ic_short_text.xml new file mode 100644 index 00000000..aeaca333 --- /dev/null +++ b/app/src/main/res/drawable/ic_short_text.xml @@ -0,0 +1,5 @@ + + + diff --git a/app/src/main/res/menu/connection_payload.xml b/app/src/main/res/menu/connection_payload.xml new file mode 100644 index 00000000..afd680ad --- /dev/null +++ b/app/src/main/res/menu/connection_payload.xml @@ -0,0 +1,20 @@ + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 8b3672dd..1884bcc7 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -314,4 +314,7 @@ Traffic No application data has been exchanged Waiting data + Display as… + Printable text + Hexdump