{"record":{"id":"15b533354ed28815","repo":"shwenzhang/AndResGuard","slug":"writetable-package-count-is-different-before-d-now-d","errorCode":null,"errorMessage":"writeTable package count is different before %d, now %d","messagePattern":"writeTable package count is different before (.+?), now (.+?)","errorType":"exception","errorClass":"brut.androlib.AndrolibException","httpStatus":null,"severity":"error","filePath":"AndResGuard-core/src/main/java/com/tencent/mm/androlib/res/decoder/ARSCDecoder.java","lineNumber":225,"sourceCode":"    mMappingWriter.close();\n    System.out.printf(\"resources mapping file %s done\\n\", mApkDecoder.getResMappingFile().getAbsolutePath());\n    generalFilterEnd(mMergeDuplicatedResCount, mMergeDuplicatedResTotalSize);\n    mMergeDuplicatedResMappingWriter.close();\n    System.out.printf(\"resources filter mapping file %s done\\n\", mApkDecoder.getMergeDuplicatedResMappingFile().getAbsolutePath());\n    return packages;\n  }\n\n  private void writeTable() throws IOException, AndrolibException {\n    System.out.printf(\"writing new resources.arsc \\n\");\n    mTableLenghtChange = 0;\n    writeNextChunkCheck(Header.TYPE_TABLE, 0);\n    int packageCount = mIn.readInt();\n    mOut.writeInt(packageCount);\n\n    mTableLenghtChange += StringBlock.writeTableNameStringBlock(mIn, mOut, mTableStringsResguard);\n    writeNextChunk(0);\n    if (packageCount != mPkgs.length) {\n      throw new AndrolibException(String.format(\"writeTable package count is different before %d, now %d\",\n         mPkgs.length,\n         packageCount\n      ));\n    }\n    for (int i = 0; i < packageCount; i++) {\n      mCurPackageID = i;\n      writePackage();\n    }\n    // 最后需要把整个的size重写回去\n    reWriteTable();\n  }\n\n  private void generalFileResMapping() throws IOException {\n    mMappingWriter.write(\"res path mapping:\\n\");\n    for (String raw : mOldFileName.keySet()) {\n      mMappingWriter.write(\"    \" + raw + \" -> \" + mOldFileName.get(raw));\n      mMappingWriter.write(\"\\n\");\n    }","sourceCodeStart":207,"sourceCodeEnd":243,"githubUrl":"https://github.com/shwenzhang/AndResGuard/blob/e4df245d82f27d9a2d0dd108260a3510cbaba849/AndResGuard-core/src/main/java/com/tencent/mm/androlib/res/decoder/ARSCDecoder.java#L207-L243","documentation":"writeTable reads the package count from the original resources.arsc and validates it against the number of ResPackage objects produced during decode (mPkgs.length). If they differ, the in-memory package set no longer matches the arsc being rewritten — an internal consistency invariant — so AndResGuard aborts rather than writing a corrupt resource table.","triggerScenarios":"Calling ARSCDecoder.write with pkgs whose length differs from the packageCount stored in the input arsc — e.g. packages added/removed after decode, decode of one arsc combined with write of another, or shared-library/multi-package APKs decoded into fewer packages than declared.","commonSituations":"Custom pipelines filtering or merging ResPackage arrays between decode and write; processing APKs with package counts AndResGuard mishandles (some split/dynamic-feature APKs); mixing streams from two different APKs.","solutions":["Pass the exact ResPackage[] returned by ARSCDecoder.decode to ARSCDecoder.write — do not add, remove, or reorder packages.","Ensure the input arsc stream in write() is the same file decoded earlier.","If processing split APKs, run AndResGuard per APK rather than merging resources across them.","Update AndResGuard — some arsc variants (shared libraries, package id offsets) were fixed in later versions."],"exampleFix":"// before\nResPackage[] pkgs = ARSCDecoder.decode(in, decoder);\nResPackage[] filtered = keepOnly(pkgs); // count no longer matches arsc\nARSCDecoder.write(in, decoder, filtered);\n// after\nResPackage[] pkgs = ARSCDecoder.decode(in, decoder);\nARSCDecoder.write(in, decoder, pkgs); // unchanged array","handlingStrategy":"validation","validationCode":"if (pkgs.length != expectedPackageCountFromArsc) {\n    throw new IllegalStateException(\"package array must be passed unchanged from decode\");\n}","typeGuard":null,"tryCatchPattern":"try {\n    ARSCDecoder.write(in, decoder, pkgs);\n} catch (AndrolibException e) {\n    if (e.getMessage().contains(\"package count is different\")) {\n        // you filtered/merged packages; rerun decode->write unchanged\n    }\n}","preventionTips":["Always pass the exact ResPackage[] from decode to write.","Process split APKs individually; never merge resources across them.","Use one arsc stream for both decode and write."],"tags":["arsc","invariant","package-count","apk"],"backgroundTag":"internal-invariant-violation","analyzedSha":"e4df245d82f27d9a2d0dd108260a3510cbaba849","analyzedAt":"2026-09-12T17:49:07.798Z","contentChangedAt":"2026-09-12T17:49:07.798Z","schemaVersion":2},"datasetVersion":"2026-09-16T09:17:16.951Z"}