Skip to content

Commit 7f4b605

Browse files
Enforce Visio comment save limits
1 parent 48e94a2 commit 7f4b605

2 files changed

Lines changed: 65 additions & 1 deletion

File tree

OfficeIMO.Tests/Visio.Comments.cs

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -201,6 +201,45 @@ public void LoadRejectsOversizedNativeCommentText() {
201201
Assert.Contains(VisioDocument.MaxCommentTextCharacters.ToString(), exception.Message);
202202
}
203203

204+
[Fact]
205+
public void SaveRejectsTooManyNativeComments() {
206+
string filePath = Path.Combine(Path.GetTempPath(), Guid.NewGuid() + ".vsdx");
207+
VisioDocument document = VisioDocument.Create(filePath);
208+
VisioPage page = document.AddPage("Review", 11, 8.5);
209+
for (int index = 0; index <= VisioDocument.MaxLoadedComments; index++) {
210+
page.Comments.Add(new VisioComment("Comment " + index.ToString()) {
211+
AuthorName = "Operations",
212+
AuthorInitials = "OP"
213+
});
214+
}
215+
216+
InvalidDataException exception = Assert.Throws<InvalidDataException>(() => document.Save());
217+
Assert.Contains(VisioDocument.MaxLoadedComments.ToString(), exception.Message);
218+
}
219+
220+
[Fact]
221+
public void SaveRejectsOversizedNativeCommentText() {
222+
string filePath = Path.Combine(Path.GetTempPath(), Guid.NewGuid() + ".vsdx");
223+
VisioDocument document = VisioDocument.Create(filePath);
224+
VisioPage page = document.AddPage("Review", 11, 8.5);
225+
page.AddComment(new string('x', VisioDocument.MaxCommentTextCharacters + 1), "Operations", "OP");
226+
227+
InvalidDataException exception = Assert.Throws<InvalidDataException>(() => document.Save());
228+
Assert.Contains(VisioDocument.MaxCommentTextCharacters.ToString(), exception.Message);
229+
}
230+
231+
[Fact]
232+
public void SaveRejectsCommentsPartThatExceedsUtf8ByteLimit() {
233+
string filePath = Path.Combine(Path.GetTempPath(), Guid.NewGuid() + ".vsdx");
234+
VisioDocument document = VisioDocument.Create(filePath);
235+
VisioPage page = document.AddPage("Review", 11, 8.5);
236+
VisioComment comment = page.AddComment("Byte budget", "Operations", "OP");
237+
comment.AuthorName = new string('\u20ac', checked((int)(VisioDocument.MaxCommentsPartBytes / 3L + 1024L)));
238+
239+
InvalidDataException exception = Assert.Throws<InvalidDataException>(() => document.Save());
240+
Assert.Contains(VisioDocument.MaxCommentsPartBytes.ToString(), exception.Message);
241+
}
242+
204243
private static void AssertNativeCommentPackage(
205244
string filePath,
206245
string expectedText,

OfficeIMO.Visio/VisioDocument.SaveCore.Comments.cs

Lines changed: 26 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,13 +49,17 @@ private static void WriteCommentsPart(
4949

5050
foreach (VisioPage page in pages) {
5151
foreach (VisioComment comment in page.Comments) {
52+
ValidateCommentForSave(comment);
5253
CommentAuthorKey authorKey = new(comment.AuthorName, comment.AuthorInitials, comment.AuthorResolutionId);
5354
if (!authorIds.TryGetValue(authorKey, out int authorId)) {
5455
authorId = authorIds.Count + 1;
5556
authorIds.Add(authorKey, authorId);
5657
}
5758

5859
comments.Add((page, comment, authorId));
60+
if (comments.Count > MaxLoadedComments) {
61+
throw new InvalidDataException($"Visio comments part contains more than {MaxLoadedComments} comments.");
62+
}
5963
}
6064
}
6165

@@ -104,9 +108,30 @@ private static void WriteCommentsPart(
104108
authorList,
105109
commentList));
106110

111+
string serializedComments = commentsXml.Declaration + Environment.NewLine + commentsXml.ToString(SaveOptions.DisableFormatting);
112+
ValidateCommentsXmlForSave(serializedComments);
113+
107114
using Stream stream = commentsPart.GetStream(FileMode.Create, FileAccess.Write);
108115
using StreamWriter writer = new(stream, new UTF8Encoding(false));
109-
writer.Write(commentsXml.Declaration + Environment.NewLine + commentsXml.ToString(SaveOptions.DisableFormatting));
116+
writer.Write(serializedComments);
117+
}
118+
119+
private static void ValidateCommentForSave(VisioComment comment) {
120+
string text = comment.Text ?? string.Empty;
121+
if (text.Length > MaxCommentTextCharacters) {
122+
throw new InvalidDataException($"Visio comment text exceeds {MaxCommentTextCharacters} characters.");
123+
}
124+
}
125+
126+
private static void ValidateCommentsXmlForSave(string commentsXml) {
127+
if (commentsXml.Length > MaxCommentsXmlCharacters) {
128+
throw new InvalidDataException($"Visio comments part exceeds {MaxCommentsXmlCharacters} XML characters.");
129+
}
130+
131+
int byteCount = Encoding.UTF8.GetByteCount(commentsXml);
132+
if (byteCount > MaxCommentsPartBytes) {
133+
throw new InvalidDataException($"Visio comments part exceeds {MaxCommentsPartBytes} bytes.");
134+
}
110135
}
111136

112137
private static int AssignSaveFallbackCommentId(VisioComment comment, XElement commentList) {

0 commit comments

Comments
 (0)