Skip to content

Commit e147bb2

Browse files
committed
2025.2 Patch 1 Code Drop
1 parent 8c635d0 commit e147bb2

4 files changed

Lines changed: 84 additions & 4 deletions

File tree

LICENSE.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
Copyright (c) 2025, Perforce Software, Inc. All rights reserved.
1+
Copyright (c) 2026, Perforce Software, Inc. All rights reserved.
22

33

44
BY INSTALLING OR DOWNLOADING THE SOFTWARE, YOU ARE ACCEPTING AND AGREEING TO THE TERMS OF

RELEASE.md

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -137,6 +137,16 @@ Known Limitations
137137
138138
* P4Java would not support file operations on altsync enabled clients.
139139

140+
-------------------------------------------
141+
Updates in 2025.2 Patch 1 (2025.2/2917314) (2026/03/27)
142+
143+
#2917145 (Job #131851)
144+
Added support for line endings conversion for UTF16-LE and UTF16-BE files
145+
146+
#2917177 (Job #129774)
147+
Improved UTF-8 BOM handling during sync to prevent duplicate BOM insertion
148+
and align with filesys.utf8bom configuration.
149+
140150
-------------------------------------------
141151
Updates in 2025.2 (2025.2/2872146) (2025/12/18)
142152

src/main/java/com/perforce/p4java/impl/mapbased/rpc/connection/RpcConnection.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -621,6 +621,7 @@ public String getDigest(RpcPerforceFileType fileType, File file, RpcPerforceDige
621621

622622
case FST_UTF16:
623623
digestCharset = CharsetDefs.UTF16;
624+
convertLineEndings = true;
624625
break;
625626
case FST_UTF8:
626627
digestCharset = CharsetDefs.UTF8;
@@ -663,6 +664,7 @@ public DigestResult getDigestAndSizeOfFile(RpcPerforceFileType fileType, File fi
663664
return new DigestResult(symlinkDigest, file.length());
664665
case FST_UTF16:
665666
digestCharset = CharsetDefs.UTF16;
667+
convertLineEndings = true;
666668
break;
667669
case FST_UTF8:
668670
digestCharset = CharsetDefs.UTF8;

src/main/java/com/perforce/p4java/impl/mapbased/rpc/sys/RpcOutputStream.java

Lines changed: 71 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -319,10 +319,11 @@ public long writeConverted(byte[] sourceBytes) throws IOException, FileDecoderEx
319319
len = sourceBytes.length;
320320
start = 0;
321321
int bom = 0;
322+
boolean isGunZipType = isGunzipFileType(this.fileType);
322323

323-
if (writeUtf8Bom) {
324-
this.write(new byte[]{(byte) 0xEF, (byte) 0xBB, (byte) 0xBF}, 0, 3);
325-
bom = 3;
324+
if (!isGunZipType) {
325+
bom = addUtf8BomIfNeeded(sourceBytes);
326+
sourceBytes = removeUtf8BomIfNeeded(sourceBytes);
326327
writeUtf8Bom = false;
327328
}
328329

@@ -392,6 +393,11 @@ public long writeConverted(byte[] sourceBytes) throws IOException, FileDecoderEx
392393
case FST_XTEXT_GUNZIP:
393394
case FST_XUTF8_GUNZIP:
394395
sourceBytes = decompressSourceBytes(sourceBytes);
396+
397+
bom = addUtf8BomIfNeeded(sourceBytes);
398+
sourceBytes = removeUtf8BomIfNeeded(sourceBytes);
399+
writeUtf8Bom = false;
400+
395401
if (this.lineEndStream != null) {
396402
this.lineEndStream.write(sourceBytes, start, len);
397403
} else {
@@ -440,6 +446,68 @@ public long writeConverted(byte[] sourceBytes) throws IOException, FileDecoderEx
440446
return bytesWritten;
441447
}
442448

449+
/**
450+
* Writes the UTF-8 BOM if writeUtf8Bom is true and sourceBytes does / doesn't already have one.
451+
*
452+
* @param sourceBytes the source byte array to check
453+
* @return the number of BOM bytes written (3 if BOM was added, 0 otherwise)
454+
* @throws IOException on error
455+
*/
456+
private int addUtf8BomIfNeeded(byte[] sourceBytes) throws IOException {
457+
// filesys.utf8bom = 1
458+
if (writeUtf8Bom && !hasUtf8Bom(sourceBytes)) {
459+
this.write(new byte[]{(byte) 0xEF, (byte) 0xBB, (byte) 0xBF}, 0, 3);
460+
return 3;
461+
}
462+
return 0;
463+
}
464+
465+
/**
466+
* Removes 1 UTF-8 BOM from sourceBytes if writeUtf8Bom is false and sourceBytes has one/many.
467+
* Also updates the len field to reflect the new length.
468+
*
469+
* @param sourceBytes the source byte array to process
470+
* @return the sourceBytes
471+
*/
472+
private byte[] removeUtf8BomIfNeeded(byte[] sourceBytes) {
473+
//filesys.utf8bom = 0
474+
if (!writeUtf8Bom && hasUtf8Bom(sourceBytes)) {
475+
byte[] newSourceBytes = new byte[sourceBytes.length - 3];
476+
System.arraycopy(sourceBytes, 3, newSourceBytes, 0, sourceBytes.length - 3);
477+
len = newSourceBytes.length;
478+
return newSourceBytes;
479+
}
480+
return sourceBytes;
481+
}
482+
483+
/**
484+
* Returns true when the first three bytes are BOM
485+
*
486+
* @param bytes
487+
* */
488+
private boolean hasUtf8Bom(byte[] bytes) {
489+
return bytes != null && bytes.length >= 3
490+
&& bytes[0] == (byte) 0xEF
491+
&& bytes[1] == (byte) 0xBB
492+
&& bytes[2] == (byte) 0xBF;
493+
}
494+
495+
/**
496+
* Returns true when the file type is GUNZIP type
497+
*
498+
* @param fileType
499+
* */
500+
private boolean isGunzipFileType(RpcPerforceFileType fileType) {
501+
return fileType == RpcPerforceFileType.FST_TEXT_GUNZIP
502+
|| fileType == RpcPerforceFileType.FST_UTF8_GUNZIP
503+
|| fileType == RpcPerforceFileType.FST_XTEXT_GUNZIP
504+
|| fileType == RpcPerforceFileType.FST_XUTF8_GUNZIP
505+
|| fileType == RpcPerforceFileType.FST_UNICODE_GUNZIP
506+
|| fileType == RpcPerforceFileType.FST_UTF16_GUNZIP
507+
|| fileType == RpcPerforceFileType.FST_XUTF16_GUNZIP
508+
|| fileType == RpcPerforceFileType.FST_XUNICODE_GUNZIP;
509+
}
510+
443511
/**
444512
* Uncompress the source bytes and store them in "tempBufferToStoreCompressedBytes"
445513
*

0 commit comments

Comments
 (0)